Socket
Socket
Sign inDemoInstall

conductor-node

Package Overview
Dependencies
9
Maintainers
1
Versions
212
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

    conductor-node

Easily integrate the entire QuickBooks Desktop API using fully-typed async TypeScript


Version published
Maintainers
1
Install size
4.33 MB
Created

Readme

Source

Conductor - The best QuickBooks Desktop integration on the planet

Execute any read or write QuickBooks Desktop API through async TypeScript and receive a fully-typed response.

qbd

Table of Contents

  1. Requirements
  2. Installation
  3. Usage
  4. APIs
  5. TypeScript
  6. Error Handling

Requirements

  1. A Conductor API key.
  2. A running version of QuickBooks Desktop connected to Conductor. See our guide to connecting QuickBooks Desktop to Conductor.

Installation

yarn add conductor-node

Usage

import Conductor from "conductor-node";

// Instantiate `Conductor` with your account's secret key.
const conductor = new Conductor("sk_test_...");

// Fetch all authorized integration-connections.
const qbdConnections = await conductor.integrationConnection.list();

// Execute any QBD API against your QBD connection id.
const newAccount = await conductor.qbd.account.add(qbdConnections[0].id, {
  Name: "Test Account",
  AccountType: "Bank",
  OpenBalance: "100",
});

APIs

integrationConnections.list()

Returns a of list all integration-connections associated with your Conductor account.

const qbdConnections = await conductor.integrationConnections.list();

integrationConnections.create(input: CreateIntegrationConnectionInput)

Creates a new integration-connection.

const newQbdConnection = await conductor.integrationConnections.create({
  // The identifier of the third-party platform to integrate.
  integrationKey: "quickbooks-desktop",
  // Your end-user's unique ID in your product's database. Must be
  // distinct from your other connections for the same integration.
  endUserSourceId: "1234-abcd",
  // Your end-user's email address for identification only. No emails
  // will be sent.
  endUserEmail: "danny@constructionco.com",
  // Your end-user's company name shown elsewhere in Conductor.
  endUserCompanyName: "Construction Corp",
});

The response looks like the following:

{
  // ❗ Save this `id` to your database for executing requests to this
  // end-user's integration in the future.
  id: 'int_conn_1234abcd',
  integrationKey: 'quickbooks-desktop',
  endUserSourceId: "1234-abcd",
  endUserEmail: 'danny@constructionco.com',
  endUserCompanyName: 'Construction Corp',
}

integrationConnections.retrieve(id: string)

Retrieves the specified integration-connection.

const qbdConnection =
  await conductor.integrationConnections.retrieve(qbdConnectionId);

integrationConnections.ping(id: string)

Checks whether the specified integration-connection can connect and process requests end-to-end.

If the connection fails, the error we encountered will be thrown as a ConductorError (like any request). This information is useful for showing a "connection status" indicator in your app. If an error occurs, we recommend displaying the property error.endUserMessage to your end-user in your app's UI.

Using async/await:

try {
  await conductor.integrationConnections.ping(qbdConnectionId);
} catch (error) {
  if (error instanceof ConductorError) {
    // Update your app's UI to display `error.endUserMessage`.
  }
  // ...
}

Or in the form of a rejected promise:

conductor.integrationConnections.ping(qbdConnectionId).catch((error) => {
  if (error instanceof ConductorError) {
    // Update your app's UI to display `error.endUserMessage`.
  }
  // ...
});

qbd.*

Executes any QuickBooks Desktop (QBD) API against a specific integration-connection id. See the official QuickBooks Desktop API Reference for a complete list of available APIs.

const newAccount = await conductor.qbd.account.add(qbdConnectionId, {
  Name: "Test Account",
  AccountType: "Bank",
  OpenBalance: "100",
});

TypeScript

Access the entire QuickBooks Desktop API through TypeScript. The qbd.* APIs are fully typed with inline documentation and will autocomplete in your editor.

To manually access the QBD types, import them from conductor-node like so:

import { QbdTypes } from "conductor-node";

const accountAddInput: QbdTypes.AccountAdd = {
  Name: "Test Account",
  AccountType: "Bank",
  OpenBalance: "100",
};

Error Handling

ConductorError

All errors thrown by the Conductor API are instances of ConductorError or its subclasses. These errors have the following properties:

PropertyTypeDescription
messagestringThe developer-friendly error message for your logs.
endUserMessagestringThe end-user-friendly error message to display in your app's UI to your end-users.

This value exists for every error. E.g., for a QBD connection error, it might recommend the end-user to check that their QuickBooks Desktop is open and that they're logged in. But if a Conductor API key is expired, e.g., this message will just say "An internal server error occurred. Please try again later.".
typestringCategorizes the error. See Error Types below.

This value is the same as the subclass name. E.g., "ConductorIntegrationError" or "ConductorInvalidRequestError".
codestringThe unique error code from Conductor, which is useful for adding special handling for specific errors. E.g., "RESOURCE_MISSING", "API_KEY_INVALID", or "QBD_REQUEST_ERROR".

In contrast, type is more general and categorizes the error.
httpStatusCodenumber or undefinedThe HTTP status code of the response that included the error.
integrationCodestring or undefinedThe unique error code supplied by the third-party integration for errors returned by the integration (i.e., ConductorIntegrationError) or integration connector (i.e., ConductorIntegrationConnectorError). This is useful for adding special handling for specific errors from the third-party integration or connector.

The integration's corresponding error message for this code is in error.message.

The third-party integrations' error codes are not standardized, so you should not rely on this code to be the same across integrations.
requestIdstring or undefinedThe unique identifier for the request that caused the error.

If you need to contact us about a specific request, providing the request identifier will ensure the fastest possible resolution.
headersobject or undefinedThe headers of the response that included the error.

Error Types

The error object you receive will have one of the following error types:

NameDescription
ConductorIntegrationErrorRaised when the third-party integration encounters an error while processing the end-user's request. This often results from an issue with the request or data handling that requires your attention to resolve.

E.g., a ListID you provided was not found in QuickBooks Desktop, or an accounting value you supplied did not adhere to the integration's accounting rules.

Refer to error.integrationCode for the error code returned by the integration, if available.
ConductorIntegrationConnectionErrorRaised when a connection error occurs with the third-party integration on the end-user's side. This typically indicates an issue with the end-user's integration-connection or configuration, which they must resolve. In other words, you cannot take action to fix these errors.

E.g., QuickBooks Web Connector (QBWC) failed to connect to QuickBooks Desktop on the end-user's computer.

Refer to error.integrationCode for the error code returned by the integration connector, if available.

❗ We recommend not alerting your team for these errors because only the end-user can fix them. See Global Error Handling for an example of this.
ConductorInvalidRequestErrorRaised when you make an API call with the wrong parameters, in the wrong state, or in an invalid way.
ConductorAuthenticationErrorRaised when Conductor cannot authenticate you with the credentials you provided. E.g., an incorrect API key.
ConductorPermissionErrorRaised when you attempt to access a resource that is not allowed.
ConductorConnectionErrorRaised when there was a network problem between the client (on your server) and Conductor's servers. E.g., a downed network or a bad TLS certificate.
ConductorInternalErrorRaised when something went wrong on Conductor's end. (These are rare.)

Specific Error Handling

If you need special handling for specific errors, you can wrap individual API calls, as shown below.

Using async/await:

try {
  const newAccount = await conductor.qbd.account.add(qbdConnectionId, {
    Name: "Test Account",
    AccountType: "Bank",
    OpenBalance: "100",
  });
} catch (error) {
  if (error instanceof ConductorError) {
    // Check `error.code`, `error.integrationCode`, etc., for special handling.
  } else {
    // ...
  }
}

Or in the form of a rejected promise:

conductor.qbd.account
  .add(qbdConnectionId, {
    Name: "Test Account",
    AccountType: "Bank",
    OpenBalance: "100",
  })
  .then((newAccount) => {
    // ...
  })
  .catch((error) => {
    if (error instanceof ConductorError) {
      // Check `error.code`, `error.integrationCode`, etc., for special handling.
    } else {
      // ...
    }
  });

Global Error Handling

It is unnecessary to wrap each API call individually, as demonstrated in the examples above. Instead, we suggest implementing a Global error handler for your server, such as app.use((error, ...) => { ... }) in Express or formatError in Apollo Server. Within this handler, perform the following actions:

  1. For any ConductorError instance, display the error.endUserMessage property to the end-user in your app's UI while logging the complete error object.
  2. For all ConductorError instances, transmit the full error object to your error-tracking service (e.g., Sentry):
    • Send a warning for instances of ConductorIntegrationConnectionError, which are not actionable by you and can only be resolved by the end-user; for example, failure to connect to QuickBooks Desktop on the end-user's computer.
    • Send an error for all other ConductorError instances, such as an invalid API key.

For example, using an Express error handler:

import * as Sentry from "@sentry/node";
import {
  ConductorError,
  ConductorIntegrationConnectionError,
} from "conductor-node";
// ...
app.use((error, req, res, next) => {
  if (error instanceof ConductorError) {
    Sentry.captureException(error, {
      level:
        error instanceof ConductorIntegrationConnectionError
          ? "warning"
          : "error",
    });
    // Return a different error message for your end-user to see in your
    // app's UI.
    res.status(500).send({ error: { message: error.endUserMessage } });
  } else {
    // ...
  }
});

Or using Apollo Server's error handler:

import { ApolloServer } from "@apollo/server";
import { unwrapResolverError } from "@apollo/server/errors";
import * as Sentry from "@sentry/node";
import {
  ConductorError,
  ConductorIntegrationConnectionError,
} from "conductor-node";
// ...
const server = new ApolloServer({
  // ...
  formatError: (formattedError, error) => {
    const origError = unwrapResolverError(error);
    if (origError instanceof ConductorError) {
      Sentry.captureException(origError, {
        level:
          origError instanceof ConductorIntegrationConnectionError
            ? "warning"
            : "error",
      });
      return {
        ...formattedError,
        // Return a different error message for your end-user to see in
        // your app's UI.
        message: origError.endUserMessage,
      };
    }
    // ...
    return formattedError;
  },
});

Keywords

FAQs

Last updated on 21 Aug 2023

Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc