Exploring the Quickbooks Online Accounting API

In this article, you'll understand how the API works, how you can connect to it, and how you can actually use it to perform various tasks, such as automatically updating accounts, invoices, bills, and more. Furthermore, you'll learn about the Apideck Unified API platform that simplifies the entire process.

Naman Bansal

Naman Bansal

32 min read
hero

Exploring the Quickbooks Online Accounting API

QuickBooks is the leading business accounting software, with a market share close to 85 percent, offering a comprehensive suite of tools, such as invoicing, estimates, instant business loans, and detailed reports.

It's quite powerful on its own, but what if you could integrate it with the rest of your tech stack? Imagine automating financial report generation with data from your sales platform or perfectly synchronized invoices and payment information between your e-commerce store and QuickBooks.

That's precisely where the QuickBooks Online Accounting API comes in, allowing you to programmatically manage your QuickBooks account, create scripts to directly interact with QuickBooks, and integrate with a selection of other services.

In this article, you'll understand how the API works, how you can connect to it, and how you can actually use it to perform various tasks, such as automatically updating accounts, invoices, bills, and more. Furthermore, you'll learn about the Accounting API offered by Apideck that simplifies the entire process.

The QuickBooks Online Accounting API

QuickBooks Online

The QuickBooks Online Accounting API uses the REST framework to provide apps with access to the customer-facing features in the software. The API is broken down into several entities that you can use to access different parts of the app. For example, the Bill entity has various details and fields about individual bills, such as vendor reference, currency reference, transaction date, amount, and due date.

It utilizes standard HTTP methods (GET, POST, PUT, DELETE) and returns JSON objects, making it compatible with a wide range of languages and frameworks, like Python, Java, TypeScript, and PHP. The API provides unique abilities apart from basic create, read, update, and delete (CRUD) operations, such as the following:

  • Single requests: The server individually processes and responds to each single request.
  • Query requests: Use the Intuit SQL-like query language to send a query to the server.
  • Batch operations: A single batch request can perform multiple actions at once.

The API is free and has no volume limits, but there is a per-minute throttling limit (max 500 requests per minute) for sending requests. It also provides free sandbox accounts. If you want to use it with your own real QuickBooks account, you have to purchase a paid plan to create an account (the API is free regardless). Pricing for QuickBooks Online varies depending on the plan.

Challenges with the QuickBooks Online Accounting API

It isn't all sunshine and rainbows, though, and there are numerous roadblocks you may face along the way.

One of the biggest challenges with the QuickBooks Online Accounting API is implementing proper authentication via OAuth 2.0. This ensures that your app securely accesses a user's QuickBooks account without compromising their privacy.

The authentication process requires users to grant access to their QuickBooks account, after which QuickBooks sends the developer an access token and a refresh token to get data from the user's account. However, the access token is valid for only one hour, after which you must use the refresh token to reset the access token. On top of that, the refresh token is valid for one hundred days, after which you will have to redo the entire authorization flow. However, this expiry date is rolling and extends each time it’s used to refresh an access token So, if you refresh the token before the end of this period, you won't have to go through the flow again. Still, It can be challenging to build this logic without disrupting the user experience.

Error handling is another crucial aspect that can be quite complex. It provides a variety of error codes and messages that detail why a request may have failed. For example, the following are common HTTP status code responses:

  • 400 Bad Request typically signifies incorrect input data, such as missing required fields for an invoice. You must validate your requests to ensure all necessary information is included.
  • 401 Unauthorized occurs due to expired access tokens or invalid credentials.
  • 403 Forbidden means the URL exists but it's restricted.

Along with these, the QuickBooks response also includes a separate error code that may be mapped to specific issues, as seen in their documentation. You must establish a well-defined error-handling strategy that interprets and captures these error codes and their details.

You must also familiarize yourself with the request and response structures to use the API effectively. It has many different endpoints for each feature, such as invoices, accounts, bills, customers, and employees; and each endpoint has different requirements. Use their documentation to look up the requirements for each one of them and ensure you don't send bad requests.

It can also become difficult to parse the API responses or create the JSON payloads, which often contain many complex nested objects. Since many API operations require asynchronous operations and handling, especially when dealing with long-running operations, a clear understanding of managing promise chains and callbacks is necessary.

Lastly, while the sandbox environment provides a useful platform for testing, it offers only a limited data set. This limitation means that it cannot fully replicate the myriad errors and scenarios you may encounter in a live environment. Real-world testing is essential for developing a comprehensive understanding of how to address various issues that may arise during actual use.

Authentication and Integration with the QuickBooks Online Accounting API

In this section, you'll learn how to authenticate the QuickBooks Online Accounting API and get your access and refresh tokens.

Head over to https://developer.intuit.com/ and click the Sign Up button.

Intuit Developer Sign Up button

Fill in your account details, and then navigate to the Sandbox option from the profile menu. If you don't find a sandbox company already created, click the Add a sandbox company button:

Sandbox companies page

Next, go to the Dashboard tab and click Create an app. Select QuickBooks Online and Payments as the platform you want to develop for:

Create an app

Give your app a name and tick only the com.intuit.quickbooks.accounting option for the scope:

App scope

Now, navigate to the Keys & credentials within the Development Settings option and get the Client ID and Client Secret:

Client ID and secret

If you're interested, you can find the GitHub repo for the full code here.

You'll use the following libraries in your code, so you need to download them with npm or another package manager:

  • Express: It's a lightweight framework for building server-side apps in Node.js. You'll use it to create a server that can handle the routing for OAuth 2.0, like handling the callback with authorization codes.
  • Axios: It's used to make HTTP requests to external APIs, including QuickBooks in this case.
  • dotenv: It's used to load environment variables from a .env file into process.env to use in the code.
  • body-parser: A middleware for Express that parses incoming request bodies in a middleware before your handlers, making it easier to extract and work with data sent in requests, such as JSON payloads. This enables our application to handle data when interacting with the QuickBooks API.

This tutorial uses Visual Studio Code, which you can download from their official page.

You can store sensitive data like the client ID, secret, and redirect URI in a .env file, as in the following snippet:

# .env
CLIENT_ID="YOUR_CLIENT_SECRET_COPIED_EARLIER"
CLIENT_SECRET="YOUR_CLIENT_SECRET_COPIED_EARLIER"
REDIRECT_URI="http://localhost:3000/callback"

Navigate to the Keys page in your Intuit Developer account and update the Redirect URIs > LINK field with the value http://localhost:3000/callback. Ensure that this value exactly matches both your .env and your Intuit Developer account:

Callback URL

Before getting into the actual code, let's briefly review how the authorization process works:

Authorization process

As seen in this diagram, you first send a GET request to a QuickBooks endpoint where the user authorizes access to their account. Then, that page redirects you to the redirect_uri specified in your .env file and includes the authorization code.

Next, you send a POST request to another endpoint that allows you to exchange this authorization code with the access and refresh tokens used to access user data.

The first thing you must do is visit the QuickBooks authorization page:

app.get('/auth', (req: Request, res: Response) => {
    const redirectUri = encodeURIComponent(process.env.REDIRECT_URI!);
    const authUrl = `https://appcenter.intuit.com/connect/oauth2?client_id=${process.env.CLIENT_ID}&response_type=code&scope=com.intuit.quickbooks.accounting&redirect_uri=${redirectUri}&state=demo-app`;
    res.redirect(authUrl);
});

Here, you retrieve the redirect URI from the environment variables and encode it to ensure it's correctly formatted. Next, the authUrl is constructed with crucial data, such as the client_id, client_secret, response_type, and state, encoded as URL query parameters.

Refer to the QuickBooks documentation for a primer on what all these terms mean.

Finally, you're instructing the browser to redirect you to the constructed authUrl.

The following code handles the callback, retrieves the authorization code, and exchanges it for the access and refresh tokens:

# app.ts

app.get('/callback', async (req: Request, res: Response) => {
    const authCode = req.query.code as string;
    const realmId = req.query.realmId as string;
    BASE_URL = `https://sandbox-quickbooks.api.intuit.com/v3/company/${realmId}`;

    if (!authCode) {
        return res.status(400).send('No authorization code received');
    }

    const requestBody = new URLSearchParams({
        grant_type: 'authorization_code',
        code: authCode,
        redirect_uri: process.env.REDIRECT_URI!,
    }).toString();

    const response = await axios.post(
        'https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer',
        requestBody,
        {
            headers: {
                'Accept': 'application/json',
                'Authorization': `Basic ${Buffer.from(`${process.env.CLIENT_ID}:${process.env.CLIENT_SECRET}`).toString('base64')}`,
                'Content-Type': 'application/x-www-form-urlencoded'
            }
        }
    );

    accessToken = response.data.access_token;
    refreshToken = response.data.refresh_token;

    res.json({ accessToken, refreshToken });
    console.log(accessToken, refreshToken);
});

Here, you're making a POST request to the endpoint, passing in the body object and the headers. The try-catch block assists with error handling and fixing any possible issues. Similarly, you can implement the refresh token logic to refresh the access code every sixty minutes:

async function refreshAccessToken() {
    if (!refreshToken) {
        console.error('No refresh token available to refresh access token');
        return;
    }

    const requestBody = new URLSearchParams({
        grant_type: 'refresh_token',
        refresh_token: refreshToken,
    }).toString();

    const response = await axios.post(
        'https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer',
        requestBody,
        {
            headers: {
                'Accept': 'application/json',
                'Authorization': `Basic ${Buffer.from(`${process.env.CLIENT_ID}:${process.env.CLIENT_SECRET}`).toString('base64')}`,
                'Content-Type': 'application/x-www-form-urlencoded'
            }
        }
    );

    // Store the new access and refresh tokens
    accessToken = response.data.access_token;
    refreshToken = response.data.refresh_token;

    console.log('Access token refreshed:', accessToken);
    console.log('Refresh token:', refreshToken);

    // Here, store the new tokens in your database or persistent storage if needed
}

setInterval(refreshAccessToken, 3600000);

In this code snippet, you're first checking if a refresh token exists. Then, you're sending a request to the same endpoint as the callback logic with the only difference being that this time, grant_type is now refresh_token instead of authorization_code, as seen in the previous code block.

The setInterval function triggers this function every 60 hours or 3,600,000 milliseconds.

Using the API

Once you're done with the authentication and have the access token, you can use the API to manipulate the sandbox QuickBooks account.

Create, Get, and Update Accounts

Accounts refer to categories that can track a business's money in and money out.

To create an account, you send a POST request, as follows:

# app.ts

const accountData = {
    "Name": "Test_Account",
    "AccountType": "Accounts Receivable"
};

const response = await axios.post(
    `${BASE_URL}/account`,
    accountData,
    {
        headers: {
            'Authorization': `Bearer ${accessToken}`,
            'Content-Type': 'application/json',
            'Accept': 'application/json',
        },
    }
);

res.status(201).json(response.data);

Created account

Now, to retrieve a specific account, you need to send only a GET request to the URL: BASE_URL/account/account_id.

The function looks something like this:

const response = await axios.get(
    `${BASE_URL}/account/91`,
    {
        headers: {
            'Authorization': `Bearer ${accessToken}`,
            'Content-Type': 'application/json',
            'Accept': 'application/json',
        },
    }
);

res.status(200).json(response.data);

This code has 91 in the base URL as that was the ID of the account created in the previous step.

Finally, let's cover how to update an account. You need to send a POST request to the URL ${BASE_URL}/account with a body containing all the fields of the object. Any writable fields omitted in the body are set to NULL.

For example, to update the name of the previous account from Test_Account to Test_Account_Updated, you'd write the following:

const accountData = {
    "Name": "Test_Account_Updated",
    "SubAccount": false,
    "FullyQualifiedName": "Test_Account_Updated",
    "Active": true,
    "Classification": "Asset",
    "AccountType": "Accounts Receivable",
    "AccountSubType": "AccountsReceivable",
    "CurrentBalance": 0,
    "CurrentBalanceWithSubAccounts": 0,
    "CurrencyRef": { "value": "USD", "name": "United States Dollar" },
    "domain": "QBO",
    "sparse": false,
    "Id": "91",
    "SyncToken": "0",
    "MetaData": { "CreateTime": "2024-08-12T09:37:38-07:00", "LastUpdatedTime": "2024-08-12T09:37:38-07:00" },
};

const response = await axios.post(
    `${BASE_URL}/account`,
    accountData,
    {
        headers: {
            'Authorization': `Bearer ${accessToken}`,
            'Content-Type': 'application/json',
            'Accept': 'application/json',
        },
    }
);

res.status(201).json(response.data);

In return, you get this object:

{"Account":{"Name":"Test_Account_Updated","SubAccount":false,"FullyQualifiedName":"Test_Account_Updated","Active":true,"Classification":"Asset","AccountType":"Accounts Receivable","AccountSubType":"AccountsReceivable","CurrentBalance":0,"CurrentBalanceWithSubAccounts":0,"CurrencyRef":{"value":"USD","name":"United States Dollar"},"domain":"QBO","sparse":false,"Id":"91","SyncToken":"1","MetaData":{"CreateTime":"2024-08-12T09:37:38-07:00","LastUpdatedTime":"2024-08-12T11:17:56-07:00"}},"time":"2024-08-12T11:17:56.425-07:00"}

Create, Get, and Update Invoices

To create an invoice using the QuickBooks Online Accounting API, you set up an endpoint called /create-invoice and send a POST request with the required invoice data. Here's how that works:

const invoiceData = {
    "CustomerRef": {
        "value": "1" // Replace with the appropriate customer ID
    },
    "Line": [
        {
            "Amount": 100.00,
            "DetailType": "SalesItemLineDetail",
            "SalesItemLineDetail": {
                "ItemRef": {
                    "value": "1", // Replace with the appropriate item ID
                    "name": "Item Name"
                },
                "UnitPrice": 100.00,
                "Qty": 1
            }
        }
    ],
    "BillAddr": {
        "Line1": "123 Main St",
        "City": "Anytown",
        "CountrySubDivisionCode": "CA",
        "PostalCode": "12345"
    },
    "CurrencyRef": {
        "value": "USD"
    }
};

const response = await axios.post(
    `${BASE_URL}/invoice`,
    invoiceData,
    {
        headers: {
            'Authorization': `Bearer ${accessToken}`,
            'Content-Type': 'application/json',
            'Accept': 'application/json',
        },
    }
);

res.status(201).json(response.data);

In this code snippet, you define the data for the invoice in the invoiceData object, consisting of the following components:

  • CustomerRef identifies the customer for whom the invoice is created. The value field must contain the ID of an existing customer in your QuickBooks account.

  • Line is an array of line items for the invoice. Each object in the array represents an individual item being billed:

    • Amount is the total amount for this specific line.
    • DetailType indicates the type for this line item. For sales items, this should be SalesItemLineDetail.
    • SalesItemLineDetail is a nested object that contains details specific to the item:
      • ItemRef references the item being billed. The value field should be the ID of the item, and name is the item's name.
      • UnitPrice is the price of one unit of the item.
      • Qty is the quantity of the item included in the invoice.
  • BillAddr is an optional object for the billing address details for the customer, helping to clarify where the invoice is to be sent.

  • CurrencyRef identifies the currency in which the invoice is issued. The value USD signifies that the invoice is in US dollars.

To read or retrieve a specific invoice, you send a GET request to the URL specified with the invoice ID: BASE_URL/invoice/invoice_id. Here's an example of how that might look:

 const { invoiceId } = req.params; // Get invoice ID from request parameters

const response = await axios.get(
    `${BASE_URL}/invoice/${invoiceId}`,
    {
        headers: {
            'Authorization': `Bearer ${accessToken}`,
            'Content-Type': 'application/json',
            'Accept': 'application/json',
        },
    }
);

Upon a successful request, you receive the invoice details in JSON format, including all information about the customer, line items, and billing address.

To update an existing invoice, you send a POST request to the URL BASE_URL/invoice with a JSON object containing the updates. The sparse:true field indicates that it's a sparse update where other fields are left untouched except the ones being updated.

You need to include the invoice's Id and SyncToken in the request. Here's how you can structure the update:

const invoiceData = {
    "Id": "145", // Replace with the invoice ID you want to update
    "SyncToken": "0", // Must be the current SyncToken for the invoice
    "Line": [
        {
            "Amount": 150.00,
            "DetailType": "SalesItemLineDetail",
            "SalesItemLineDetail": {
                "ItemRef": {
                    "value": "1", // ID of the item
                    "name": "Updated Item Name" // Optional updated item name
                },
                "UnitPrice": 150.00,
                "Qty": 1
            }
        }
    ]
};

const response = await axios.post(
    `${BASE_URL}/invoice`,
    invoiceData,
    {
        headers: {
            'Authorization': `Bearer ${accessToken}`,
            'Content-Type': 'application/json',
            'Accept': 'application/json',
        },
    }
);

res.status(200).json(response.data);

Create, Get, and Update Bills

To create a bill, set up an endpoint called /create-bill and send a POST request with the required bill data. Here's how that works:

const billData = {
    "VendorRef": {
        "value": "56"
    },
    "Line": [
        {
            "Amount": 100.00,
            "DetailType": "AccountBasedExpenseLineDetail",
            "AccountBasedExpenseLineDetail": {
                "AccountRef": {
                    "value": "7",
                }
            }
        }
    ],
    "CurrencyRef": {
        "value": "USD"
    }
};

const response = await axios.post(
    `${BASE_URL}/bill`,
    billData,
    {
        headers: {
            'Authorization': `Bearer ${accessToken}`,
            'Content-Type': 'application/json',
            'Accept': 'application/json',
        },
    }
);

res.status(201).json(response.data);

In this code snippet, you define the data for the bill in the billData object, which includes these components:

  • VendorRef identifies the vendor to whom the bill is addressed. The value field must contain the ID of an existing vendor in your QuickBooks account.

  • Line is an array of line items for the bill. Each object in the array represents an individual expense being billed:

    • Amount is the total amount for this specific line.
    • DetailType indicates the type for this line item. For expense items, this should be ExpenseLineDetail.
    • ExpenseLineDetail is a nested object that contains details specific to the expense:
      • AccountRef references the account associated with this expense. The value field should be the ID of the account, and name is the account's name.
      • Amount is the total amount for this line item.
      • Qty is the quantity of the item included in the bill.
  • CurrencyRef identifies the currency in which the bill is issued. The value USD signifies that the bill is in US dollars.

To read or retrieve a specific bill, you send a GET request to the URL specified with the bill ID: BASE_URL/bill/bill_id. Here's an example of how that might look:

const response = await axios.get(
    `${BASE_URL}/bill/1`, // Replace 1 with the actual bill ID
    {
        headers: {
            'Authorization': `Bearer ${accessToken}`,
            'Content-Type': 'application/json',
            'Accept': 'application/json',
        },
    }
);

To update an existing bill, you send a POST request to the URL ${BASE_URL}/bill with a JSON object containing the updates. Remember to include the bill's Id and SyncToken in the request.

Also, since it's a full update, any fields not included in the request are changed to NULL.

Here's how you can structure the update:

const billData = {
    "Id": "146", // Replace with the bill ID you want to update
    "SyncToken": "0",
    "DueDate": "2024-08-12",
    "TotalAmt": 150,
    // Other fields as necessary
};

const response = await axios.post(
    `${BASE_URL}/bill`,
    billData,
    {
        headers: {
            'Authorization': `Bearer ${accessToken}`,
            'Content-Type': 'application/json',
            'Accept': 'application/json',
        },
    }
);

res.status(200).json(response.data);

Create, Get, and Update Payments

Payments are essential for tracking monetary transactions made toward invoices or outstanding balances.

QuickBooks has specific features and requirements for payments, which include the following:

  • The ability to perform either full or sparse updates.
  • The capability to link to multiple invoices or credit memos.
  • The option to record a payment without linking it to any specific invoice or credit memo.
  • Regardless of whether a full or sparse update is performed, the Line field must always contain all relevant line items.

To create a payment, set up an endpoint called /create-payment that sends a POST request with the required payment data:

const paymentData = {
    "CustomerRef": {
        "value": "1" // Replace with the appropriate customer ID
    },
    "TotalAmt": 100,
    "Line": [
        {
            "Amount": 100.00, // Total payment amount for this line
            "LinkedTxn": [
                {
                    "TxnId": "1", // Replace with the ID of the invoice being paid
                    "TxnType": "Invoice" // The type of transaction
                }
            ]
        }
    ],
    "CurrencyRef": {
        "value": "USD" // Currency code for the payment
    }
};

const response = await axios.post(
    `${BASE_URL}/payment`,
    paymentData,
    {
        headers: {
            'Authorization': `Bearer ${accessToken}`,
            'Content-Type': 'application/json',
            'Accept': 'application/json',
        },
    }
);

res.status(201).json(response.data);

The code snippet includes the following fields:

  • CustomerRef identifies the customer making the payment.

  • Line contains details about the payment, including the following:

    • Amount is the total payment amount.
    • LinkedTxn links the payment to the invoice(s) being paid, requiring the transaction ID (TxnId) and transaction type (TxnType).
  • PaymentMethodRef identifies how the payment is made (eg cash, credit card).

  • CurrencyRef specifies the currency in which the payment is made.

To read or retrieve a specific payment, send a GET request to the URL specified with the payment ID BASE_URL/payment/payment_id:

const { paymentId } = req.params; // Get payment ID from request parameters

const response = await axios.get(
    `${BASE_URL}/payment/${paymentId}`,
    {
        headers: {
            'Authorization': `Bearer ${accessToken}`,
            'Content-Type': 'application/json',
            'Accept': 'application/json',
        },
    }
);

res.status(200).json(response.data);

This code gets the payment ID from the request parameters and retrieves the payment details in JSON format.

To update an existing payment, send a POST request to the ${BASE_URL}/payment URL with a JSON object for the updates. Include the payment's Id and SyncToken.

Create, Get, and Update Transfers

Transfers represent the movement of money between bank accounts. To create a transfer, set up an endpoint called /create-transfer and send a POST request with the required transfer data:

const transferData = {
    "FromAccountRef": {
        "value": "1" // Replace with the source account ID
    },
    "ToAccountRef": {
        "value": "2" // Replace with the destination account ID
    },
    "Amount": 100.00, // Amount to be transferred
    "TxnDate": "2024-01-01" // Date of the transfer
};

const response = await axios.post(
    `${BASE_URL}/transfer`,
    transferData,
    {
        headers: {
            'Authorization': `Bearer ${accessToken}`,
            'Content-Type': 'application/json',
            'Accept': 'application/json',
        },
    }
);

res.status(201).json(response.data);

Here are the important attributes of the JSON object in this code snippet:

  • FromAccountRef identifies the account from which the money is being transferred.
  • ToAccountRef identifies the account to which the money is being transferred.
  • Amount is the total amount being transferred.
  • CurrencyRef specifies the currency for the transfer.
  • PaymentMethodRef identifies the method used for the transfer (eg bank transfer).
  • Date is the date when the transfer occurs.

To read or retrieve a specific transfer, send a GET request to the URL specified with the transfer ID BASE_URL/transfer/transfer_id:

const { transferId } = req.params; // Get transfer ID from request parameters

const response = await axios.get(
    `${BASE_URL}/transfer/${transferId}`,
    {
        headers: {
            'Authorization': `Bearer ${accessToken}`,
            'Content-Type': 'application/json',
            'Accept': 'application/json',
        },
    }
);

res.status(200).json(response.data);

This code retrieves the transfer details using the transfer ID provided in the request parameters.

To update an existing transfer, send a POST request to the ${BASE_URL}/transfer URL with a JSON object for the updates. Include the transfer Id and SyncToken. Since transfers support sparse updates, you'll see a code snippet for that later, but you may do a full update, too.

Here's how you could structure the update:

const transferData = {
    "Id": "145", // Replace with the transfer ID you want to update
    "SyncToken": "0", // Must be the current SyncToken for the transfer
    "Amount": 150.00, // Updated transfer amount
    "FromAccountRef": {
        "value": "1" // Source account ID
    },
    "ToAccountRef": {
        "value": "2" // Destination account ID
    },
    sparse: true
};

const response = await axios.post(
    `${BASE_URL}/transfer`,
    transferData,
    {
        headers: {
            'Authorization': `Bearer ${accessToken}`,
            'Content-Type': 'application/json',
            'Accept': 'application/json',
        },
    }
);

res.status(200).json(response.data);

Create, Get, and Update Vendors

The QuickBooks Online Accounting API has some specific rules for setting up vendors:

  • DisplayName must be unique across all customer, employee, and vendor objects.
  • PrimaryEmailAddress must contain an at (@) and dot (.) sign.

To create a vendor, set up an endpoint called /create-vendor and send a POST request with the required vendor data:

const vendorData = {
    "DisplayName": "Vendor Name", // Required: Name of the vendor
    "PrimaryEmailAddr": {
        "Address": "vendor@example.com" // Vendor's email address
    },
    "PrimaryPhone": {
        "FreeFormNumber": "(123) 456-7890" // Vendor's phone number
    },
    "BillAddr": { // Optional billing address details
        "Line1": "123 Vendor St",
        "City": "Vendor City",
        "CountrySubDivisionCode": "CA", // State abbreviation
        "PostalCode": "12345" // Postal code
    },
    "Suffix": "Sr.",
    "Title": "Mr.",
    "GivenName": "Example 1",
    "PrintOnCheckName": "Example Vendor Name"
};

const response = await axios.post(
    `${BASE_URL}/vendor`,
    vendorData,
    {
        headers: {
            'Authorization': `Bearer ${accessToken}`,
            'Content-Type': 'application/json',
            'Accept': 'application/json',
        },
    }
);

res.status(201).json(response.data);

To read or retrieve a specific vendor, send a GET request to the URL specified with the vendor ID BASE_URL/vendor/vendor_id:

const { vendorId } = req.params; // Get vendor ID from request parameters

const response = await axios.get(
    `${BASE_URL}/vendor/${vendorId}`,
    {
        headers: {
            'Authorization': `Bearer ${accessToken}`,
            'Content-Type': 'application/json',
            'Accept': 'application/json',
        },
    }
);

res.status(200).json(response.data);

This code retrieves the vendor details using the vendor ID provided in the request parameters.

To update an existing vendor, send a POST request to the ${BASE_URL}/vendor URL with a JSON object for the updates. Include the vendor's Id and SyncToken. The structure is the same as the earlier full update requests.

Webhooks

Webhooks act as instant messengers, delivering information in real-time straight to your app whenever an event occurs in your end user’s QuickBooks account. You can use this data to perform further actions or logic. For example, if your user creates a new invoice, vendor, or customer, you can instantly get a notification, which can be used for actions such as automatically updating your accounting system, sending a confirmation email, or triggering a workflow to approve or review the new entry.

Using webhooks with QuickBooks is quite simple. First, setup OAuth 2.0 authentication for your app using the steps outlined above. Then, you can specify webhook events you want to listen for and the endpoint URL where you want to receive the data in the Intuit Developer dashboard.

Once the webhook's data is validated, you can process it and perform additional logical operations. For more detailed guidance, refer to the documentation and explore code samples here.

Conclusion

This article covered the fundamental processes involved with the QuickBooks Online Accounting API, such as authorization, account creation, invoices, bills, and payments. By now, you should have a solid understanding of the request and response structure as well as how you can integrate it in your own apps.

To further simplify the process, you should check out Apideck. It's a powerful unified APIs solution that allows business-to-business software-as-a-service (B2B SaaS) companies to scale their integrations effortlessly. The Apideck Unified API enables you to create a single integration that interacts with multiple accounting systems, including QuickBooks, Xero, and Sage, as well as customer relationship management (CRM) and human resources information systems (HRIS), eliminating the need for separate point-to-point integrations. However, its main differentiator is its real-time data access, ensuring minimal delays and robust security with its no-data-storage model and SOC 2 type 2 compliance.

Get started with a free trial today.

Ready to get started?

Scale your integration strategy and deliver the integrations your customers need in record time.

Ready to get started?
Trusted by
Nmbrs
Benefex
Principal Group
Invoice2go by BILL
Trengo
MessageMedia
Lever
Ponto | Isabel Group
Subscribe to our newsletter
SOC 2 Type 2

Products

Customer cases

Resources

© 2024 Apideck. Mentioned product names and logos are the property of their respective owners.