quickbook-integration
v1.0.6
Published
QuickBooks Online integration for all products — OAuth, customer, invoice and payment management
Maintainers
Readme
quickbook-integration
QuickBooks Online integration for Node.js — OAuth 2.0, customer, invoice and payment management, built on top of intuit-oauth.
Install
npm install quickbook-integrationRequirements
- An Intuit Developer app (get one at developer.intuit.com) with:
- Client ID
- Client Secret
- A registered Redirect URI
Quick start
clientId, clientSecret and redirectUri just need to reach the constructor as strings — pull them from wherever your app keeps config (env vars, a database, a secrets manager, a config service, etc.). Env vars are used below purely as an example.
const { QuickBooksClient } = require('quickbook-integration');
// 1. Create the client once (e.g. at app startup)
// Load clientId/clientSecret/redirectUri from your own config source —
// env vars, a database row, a secrets manager... anything that gives you strings.
const qb = new QuickBooksClient({
clientId: process.env.QB_CLIENT_ID,
clientSecret: process.env.QB_CLIENT_SECRET,
redirectUri: process.env.QB_REDIRECT_URI,
isSandbox: true, // false for production
});
// 2. Start OAuth — send the user's browser to this URL
const authUrl = qb.getAuthUri(userId); // userId is echoed back as `state`
// 3. In your redirect/callback route — exchange the code for tokens
app.get('/quickbooks/callback', async (req, res) => {
const tokens = await qb.exchangeCode(req.url);
// tokens = { access_token, refresh_token, realmId, state, expires_in, x_refresh_token_expires_in }
// → save these to your database, keyed by realmId / userId
res.send('Connected to QuickBooks!');
});
// 4. On subsequent requests — load saved tokens from your DB, then create a session
const session = qb.createSession({
access_token: row.access_token,
refresh_token: row.refresh_token,
realmId: row.realmId,
lastRefreshedAt: row.date_updated, // Date or ISO string
});
// 5. Refresh the token if needed (safe to call before every API operation)
const { tokens: newTokens, refreshed } = await session.refreshIfNeeded();
if (refreshed) {
// → persist newTokens back to your DB
}
// 6. Make API calls
const customerId = await session.findCustomerByNameAndEmail('John Doe', '[email protected]');
const invoiceId = await session.createInvoice({
CustomerRef: { value: customerId },
Line: [
{
Amount: 100,
DetailType: 'SalesItemLineDetail',
SalesItemLineDetail: { ItemRef: { value: '1', name: 'Services' } },
},
],
});
const paid = await session.recordPaymentAgainstInvoice({
customerId,
invoiceId,
totalAmount: 100,
note: 'Recurring payment',
});Why sessions?
QuickBooksClient holds your app-level OAuth config (client ID/secret/redirect URI) and is safe to create once and reuse.
QuickBooksSession wraps a single company's (realmId) tokens. Each session owns its own internal OAuth client instance, so concurrent requests for different QuickBooks companies never overwrite each other's tokens. Create a new session per request/company using tokens you've loaded from your own storage — this package does not persist tokens for you.
API
new QuickBooksClient(config)
| Option | Type | Required | Description |
|---|---|---|---|
| clientId | string | ✅ | Intuit app client ID |
| clientSecret | string | ✅ | Intuit app client secret |
| redirectUri | string | ✅ | OAuth redirect URI registered in your Intuit app |
| isSandbox | boolean | – | true (default) for sandbox, false for production |
qb.getAuthUri(state)
Returns the URL to redirect the user to for QuickBooks authorization. state (string or number, e.g. a user/doctor ID) is echoed back in the callback so you can identify who just authorized.
qb.exchangeCode(callbackUrl)
Call this in your OAuth callback route with the full callback URL (including query string). Returns:
{
access_token: string;
refresh_token: string;
expires_in: number;
x_refresh_token_expires_in: number;
realmId: string; // the QuickBooks company ID
state: string;
}qb.createSession({ access_token, refresh_token, realmId, lastRefreshedAt })
Returns a QuickBooksSession for making authenticated API calls against that company.
QuickBooksSession
session.refreshIfNeeded()
Refreshes the access token if it's an hour or older. Call this before any API operation and persist the returned tokens if refreshed is true.
Promise<{ tokens: { access_token: string; refresh_token: string }; refreshed: boolean }>session.findCustomerByNameAndEmail(name, email)
Searches for a customer by display name, filtered by email. Returns the QuickBooks customer Id, or null if no match.
name is safely escaped before being placed into the underlying QuickBooks query, so names containing characters like ' (e.g. O'Brien) are handled correctly.
Promise<string | null>session.createCustomer(data)
Creates a customer. data is a QuickBooks Customer object (e.g. { DisplayName, GivenName, FamilyName, PrimaryEmailAddr }). Returns the created customer's Id.
Promise<string>session.createInvoice(data)
Creates an invoice. data is a QuickBooks Invoice object (e.g. { CustomerRef, Line, DueDate }). Returns the created invoice's Id.
Promise<string>session.createPayment(data)
Records a payment. data is a QuickBooks Payment object (e.g. { CustomerRef, TotalAmt, PrivateNote, Line }). Returns true on success, false on failure (does not throw).
Promise<boolean>session.recordPaymentAgainstInvoice({ customerId, invoiceId, totalAmount, lineAmount?, note? })
Convenience wrapper around createPayment that builds the payload (including the LinkedTxn line linking the payment to the invoice) for you.
Promise<boolean>TypeScript
Type definitions are bundled (index.d.ts) — no @types package needed.
import { QuickBooksClient, QuickBooksSession } from 'quickbook-integration';Error handling
- OAuth/API failures from
getAuthUri,exchangeCode,createCustomer,createInvoice,refreshIfNeeded, and the internal API caller throw anErrorprefixed with[quickbook-integration]. createPaymentandrecordPaymentAgainstInvoicedo not throw — they resolve tofalseon failure so you can decide how to handle it.
Changelog
- 1.0.5 —
findCustomerByNameAndEmailnow escapes thenamevalue before building the underlying QuickBooks query, fixing a query-injection gap and a functional bug where names containing'would break the lookup. - 1.0.4 — Added README, LICENSE (ISC), and
authorfield. No code changes.
License
ISC
