quickbooks-api
Version:
A modular TypeScript SDK for seamless integration with Intuit QuickBooks APIs. Provides robust authentication handling and future-ready foundation for accounting, payments, and commerce operations.
322 lines (250 loc) • 8.61 kB
text/typescript
// Imports
import express, { type Request, type Response } from 'express';
import { AuthProvider, Environment, ApiClient, AuthScopes, EstimateStatus, Invoice, InvoiceOptions, InvoiceStatus } from './src/app';
// Initialize the Express App
const app = express();
const port = process.env.PORT || 3000;
// Initialize AuthProvider
const authProvider = new AuthProvider(
process.env.QB_CLIENT_ID!,
process.env.QB_CLIENT_SECRET!,
process.env.REDIRECT_URI!,
[
AuthScopes.Payment,
AuthScopes.Accounting,
AuthScopes.OpenId,
AuthScopes.Profile,
AuthScopes.Email,
AuthScopes.Phone,
AuthScopes.Address,
], // Scopes
);
// Auth endpoint to initiate OAuth flow
app.get('/test-token', (_req: Request, res: Response) => {
// Initialize AuthProvider
const testAuthProvider = new AuthProvider(
process.env.QB_CLIENT_ID!,
process.env.QB_CLIENT_SECRET!,
'http://localhost:3000/generate-test-token',
[
AuthScopes.Payment,
AuthScopes.Accounting,
AuthScopes.OpenId,
AuthScopes.Profile,
AuthScopes.Email,
AuthScopes.Phone,
AuthScopes.Address,
], // Scopes
);
// Generate the Auth URL
const authUrl = testAuthProvider.generateAuthUrl();
// Redirect to the Auth URL
res.redirect(authUrl.toString());
});
// Auth endpoint to initiate OAuth flow
app.get('/auth', (_req: Request, res: Response) => {
// Generate the Auth URL
const authUrl = authProvider.generateAuthUrl();
// Redirect to the Auth URL
res.redirect(authUrl.toString());
});
// Callback endpoint for OAuth response
app.get('/auth-code', async (req: Request, res: Response) => {
try {
// Get the Code and Realm ID from the Request
const { code, realmId } = req.query;
// Check if the Code and Realm ID are present
if (!code || !realmId) {
res.status(400).send('Missing code or realmId in callback');
return;
}
// Exchange authorization code for tokens
await authProvider.exchangeCode(code as string, realmId as string);
// Log the progress
console.log('Exchanged code for tokens');
// Refresh the Token
await authProvider.refresh();
// Log the progress
console.log('Refreshed token');
// Initialize API Client with the authenticated provider
const apiClient = new ApiClient(authProvider, Environment.Sandbox);
// Find a Customer by ID
const foundCustomer = await apiClient.customers.getCustomerById('1');
// Log the progress
console.log(`Got found customer ${foundCustomer?.BillAddr?.PostalCode}`);
// Change the Customer Name
foundCustomer.BillAddr.PostalCode = '94326';
// Save the Customer
await foundCustomer.save();
// Log the progress
console.log(`Reloaded customer ${foundCustomer?.BillAddr?.PostalCode}`);
// Example: Get invoices using the authenticated client
const invoices = await apiClient.invoices.getAllInvoices();
// Log the progress
console.log('Got invoices');
// Get the Invoices Due Today
const dueInvoices = await apiClient.invoices.getInvoicesByDueDate(new Date());
// Log the progress
console.log('Got due invoices');
// Setup the Custom Query Builder
const customQueryBuilder = (await apiClient.invoices.getQueryBuilder()).setSearchOptions({
orderBy: { field: 'DueDate', direction: 'DESC' },
maxResults: 10,
});
// Log the progress
console.log('Got custom query builder');
// Advanced query using raw query builder
const customQuery = await apiClient.invoices.rawInvoiceQuery(customQueryBuilder);
// Log the progress
console.log('Got custom query');
// Get the First Invoice
const firstInvoice = invoices.results[0];
// Check if the First Invoice is Invalid and Return
if (!firstInvoice || !firstInvoice.Id) {
res.status(400).send('No invoices found');
return;
}
// Example: Get invoice by ID
const foundInvoice = await apiClient.invoices.getInvoiceById(firstInvoice.Id);
// Log the progress
console.log('Got found invoice');
// Example: Get invoices for a date range
const invoicesForDateRange = await apiClient.invoices.getInvoicesForDateRange(new Date('2024-01-01'), new Date('2024-01-31'));
// Log the progress
console.log('Got invoices for date range');
// Example: Get updated invoices
const updatedInvoices = await apiClient.invoices.getUpdatedInvoices(new Date('2024-01-01'));
// Log the progress
console.log('Got updated invoices');
// Setup the List of Invoices
const paginatedInvoices: Array<Invoice> = [];
// Setup the has Next Page Boolean
let hasNextPage = true;
// Setup the Page Number
let page = 1;
// Example: Get all invoices (with search options and pagination)
while (hasNextPage) {
// Setup the Invoice
const invoiceOptions: InvoiceOptions = {
searchOptions: {
maxResults: 100,
page: page,
orderBy: { field: 'Id', direction: 'DESC' },
},
};
// Get the Invoices
const searchResponse = await apiClient.invoices.getAllInvoices(invoiceOptions);
// Add the Invoices to the List
paginatedInvoices.push(...searchResponse.results);
// Check if there is a next page
hasNextPage = searchResponse.hasNextPage;
// Log the progress
console.log(`Got paginated invoices [${page}]`);
// Increment the Page Number
page++;
}
// Get the list of Paid Invoice
const paidInvoices = await apiClient.invoices.getAllInvoices({ status: InvoiceStatus.Paid });
// Example: Get all estimates
const estimates = await apiClient.estimates.getAllEstimates();
// Log the progress
console.log('Got estimates');
// Example: Get all estimates for a date range
const estimatesForDateRange = await apiClient.estimates.getEstimatesForDateRange(new Date('2025-01-01'), new Date('2025-01-31'));
// Log the progress
console.log('Got estimates for date range');
// Example: Get updated estimates
const updatedEstimates = await apiClient.estimates.getUpdatedEstimates(new Date('2025-01-09'));
// Log the progress
console.log('Got updated estimates');
// Example: Get estimate by ID
const foundEstimate = await apiClient.estimates.getEstimateById(estimates.results[0].Id);
// Log the progress
console.log('Got found estimate');
// Example: Serialize the Token
const serialized = await authProvider.serializeToken(process.env.SECRET_KEY!);
// Log the progress
console.log('Serialized token');
// Example: Deserialize the Token
await authProvider.deserializeToken(serialized!, process.env.SECRET_KEY!);
// Log the progress
console.log('Deserialized token');
// Example: Get the Token
const deserialized = await authProvider.getToken();
// Log the progress
console.log('Got token');
// Example: Revoke the Token
const revoked = await authProvider.revoke();
// Log the progress
console.log('Revoked token');
// Return the Data
res.json({
invoices,
paidInvoices,
firstInvoice,
foundInvoice,
invoicesForDateRange,
updatedInvoices,
paginatedInvoices,
dueInvoices,
customQuery,
estimates,
estimatesForDateRange,
updatedEstimates,
foundEstimate,
revoked,
serialized,
deserialized,
});
} catch (error) {
// Log the Error
console.error('Auth callback error:', error);
// Send the Error
res.status(500).send('Authentication failed');
}
});
// Callback endpoint for OAuth response
app.get('/generate-test-token', async (req: Request, res: Response): Promise<void> => {
// Initialize AuthProvider
const testAuthProvider = new AuthProvider(
process.env.QB_CLIENT_ID!,
process.env.QB_CLIENT_SECRET!,
'http://localhost:3000/generate-test-token',
[
AuthScopes.Payment,
AuthScopes.Accounting,
AuthScopes.OpenId,
AuthScopes.Profile,
AuthScopes.Email,
AuthScopes.Phone,
AuthScopes.Address,
], // Scopes
);
try {
// Get the Code and Realm ID from the Request
const { code, realmId } = req.query;
// Check if the Code and Realm ID are present
if (!code || !realmId) {
res.status(400).send('Missing code or realmId in callback');
return;
}
// Exchange authorization code for tokens
await testAuthProvider.exchangeCode(code as string, realmId as string);
// Refresh the Token
await testAuthProvider.refresh();
// Example: Serialize the Token
const serialized = await testAuthProvider.serializeToken(process.env.SECRET_KEY!);
// Return the Data
res.send(serialized);
} catch (error) {
// Log the Error
console.error('Auth callback error:', error);
// Send the Error
res.status(500).send('Authentication failed');
}
});
// Start the Server
app.listen(port, () => {
// Log the Server is Running
console.log(`Server running on port ${port}`);
});