HomeGuidesRecipesAPI ExplorerForumSupport
Partner Portal
Partner Portal

Accounting integrations

Enable your users to synchronize accounts payable and receivable data with popular accounting solutions.

Overview

Many SMEs use various accounting solutions to store their financial data and prepare it for submission to tax authorities. With Monite, you can connect your users' data to their preferred accounting software and pull necessary financial data for import into your interface, as well as push data in case they need to do any post-accounting work outside of your application.

📘

To support integration with accounting systems, Monite leverages the technology of its strategic partner, Codat, which supports a wide range of accounting systems and connections. You will also need to make a separate agreement with Codat. Please contact your Account Manager at Monite to assist in this process.

Supported accounting systems

Each entity can connect to one of the following accounting systems:

  • QuickBooks
  • Xero

    ⚠️

    Important

    If you plan to provide Xero integration to more than 25 entities, you must register with Xero as a Xero App Partner. This involves additional requirements set by Xero. The registration can take several weeks to get finalized, so we recommend that you apply as soon as possible.

New supported accounting systems will be added in future releases of our platform. If you have any specific requests, please contact our Support team.

📘

An entity can connect their data to only one accounting system. If they want to connect to another accounting system, they have to disconnect the currently connected system first.

Requirements and considerations

  • A Monite partner should make a separate arrangement with Codat to enable their services via Monite API. To learn more about this and get Monite assistance, please contact your Account Manager at Monite.
  • Each entity that wants to connect to an external accounting system (like Xero or QuickBooks) should create an account with that system and securely store login credentials, as these credentials will be needed in the future to authorize its access to their data, which is stored within the corresponding accounting system.

How the integration works

As the first step, you need to establish a connection to the accounting software of an entity and ask an entity user to authorize the connection.

Once the connection has been established, all financial data of this entity is automatically synchronized every hour.

You can track the data synchronization status in the following ways:

  • Call Monite's GET /accounting_connections/{connection_id} endpoint.
  • Review data in the Codat Portal.
  • Subscribe to Codat webhooks.

What data is synchronized

Currently, Monite pulls and pushes the following data from and to accounting systems. Data is synchronized every hour.

DataPulledPushed
Ledger accounts:heavy-check-mark:References to ledger accounts
in invoice line items, and products
Counterparts:heavy-check-mark::heavy-check-mark:
Products:heavy-check-mark:
Accounts Receivable: invoices:heavy-check-mark:
Accounts Payable: invoices (bills):heavy-check-mark:

How data is synchronized


Pulling

Pulling

Counterparts

When retrieving counterpart data from your accounting system for use in Monite, counterpart information is matched based on their names, countries, cities, and addresses—in that exact order—till there is an exact match. If there is more than one counterpart with the same name, we additionally attempt to match them based on their other information provided.

No new items are created in Monite during this process; therefore, no action is taken if no match is found. After the initial matching, Monite does not check for changes in your accounting system.

Products

All products are pulled from the accounting system on the first connection. Data is pulled and IDs are matched based on their names alone. If a product does not exist on Monite, Monite will create a new product in our database and link it to the corresponding product from your accounting system.

Following the initial matching process, data consistency is not routinely verified in response to changes in either system. If a matching pair cannot be found, no further action is taken. You can also associate specific products to specific ledger accounts by using the ledger_account_id field when creating or updating a product.

📘

Handling multiple matches

If a product's name matches with multiple products on either system, Monite does not attempt to match any of the results. The resulting error will be returned in your sync_object.


Pushing

Pushing

Accounts Payable: invoices (bills)

Before pushing, bill validation is performed to confirm the presence of references for tax_rate_ref_id, ledger_account_id, and line_items. Issuance of bills without this validation is prohibited.

Accounts Receivable: invoices

During synchronization, Monite only pushes invoices in issued, canceled, and uncollectible statuses to Codat. After pushing, invoices in canceled and uncollectible status are marked as void on Codat.

Counterparts

Counterparts from your accounting system are matched using their names. Once matched, there is no regular check for data changes in either system. If no match is found, new objects are created in the accounting system.


Limitations

Data push limitations

  • Accounts Receivable invoices with invoice-level discounts cannot be pushed to accounting systems. However, invoices with line item discounts are pushed.

Data pull limitations

  • In accounting systems, the currency is set at an entity level, while in Monite, each product can have a price in its own currency. Therefore, when pulling data from accounting systems, Monite uses the currency set at the entity level and sets it for each product.
  • Unlike Monite, Codat does not provide a separate collection of customizable measure units at the entity level. To overcome this limitation, Monite generates some stub measure units when pulling data via Codat, and entity users can always adjust this data later, if needed.

Terminology

The following table compares the terms used by Monite and Codat, so that you know which resources to examine when testing data synchronization:

Monite termCodat term
EntityCompany
Entity usern/a
CounterpartCustomer, Supplier
PayableBill
Receivable: InvoiceInvoice

Set up integration with an accounting system

1. Preliminary steps

Before you begin developing your implementation, there are some setup steps you need to complete in Codat and in the accounting systems you want to integrate with. This involves registering an app in QuickBooks Online and/or Xero platforms to get the client keys for integrating with these platforms. You will then need to enable the corresponding integrations in the Codat Portal (for both of your Codat Production instance and Test instance) and specify your app's client keys.

For the detailed instructions, refer to Codat documentation:

2. Get a Codat API key

Monite calls Codat API on behalf of a Monite partner. To do that, Monite needs a partner's encoded Codat API key. To get this key:

  1. Log in the Codat Portal.
  2. In the top right corner, select the Codat client account whose API key you need - Test instance or Production instance.
  3. Go to Developers > API > API keys.
  4. If you don't already have an API key, create one.
  5. Copy the value of the Authorization header (not the API key value). This value is in the format Basic YOUR_ENCODED_API_KEY.
  1. Remove the "Basic " prefix from the copied value, so that you have just YOUR_ENCODED_CODAT_API_KEY. This is the value you will have to specify later in your Monite partner settings.

Repeat the steps to get the encoded API keys for both Codat Test instance and Production instance. You need need to use the corresponding key with Monite Sandbox and Production environments.

3. Send Codat webhooks to Monite

In order for Monite to know the status of data synchronizations and accounting connections of your entities, you must subscribe to certain Codat webhooks and send them to Monite. The necessary Codat webhooks are:

  • Push Operation Status Changed
  • Data sync completed
  • DataConnectionStatusChanged

The Monite webhook listener URLs for accounting webhooks are:

📘

You must configure these webhooks both in Codat Test instance and Production instance. Codat Test instance should send webhooks to the Monite Sandbox environment, and Codat Production instance should send them to the Monite Production environment.

To configure the webhooks:

  1. In the Codat Portal, select your Codat client account to configure webhooks for - Test instance or Production instance.
  2. Go to Settings > Webhooks > Rules.
  3. Click Create new rule.
  4. Specify the following settings:
    • Rule type - select one of the above mentioned webhooks.
    • Company - select All companies.
    • (Optional) Email addresses to notify - a comma-separated list of email addresses where to send the notifications.
    • Webhook notification URL:
    • Click Save changes.

Repeat the steps to create the rules for all three webhooks in both Codat Test instance and Production instance.

4. Generate a Monite partner access token

To authenticate your API calls with Monite, you need to generate a new partner-level token. To do this, call POST /auth/token with the following parameters:

curl -X POST 'https://api.sandbox.monite.com/v1/auth/token' \
     -H 'X-Monite-Version: 2024-01-31' \
     -H 'Content-Type: application/json' \
     -d '{
        "grant_type": "client_credentials",
        "client_id": "YOUR_PARTNER_CLIENT_ID",
        "client_secret": "YOUR_PARTNER_CLIENT_SECRET"
     }'

The successful response contains the token and its validity time (in seconds):

{
  "access_token": "eyJ0eXAiOiJKV1QiLCJhb...",
  "token_type": "Bearer",
  "expires_in": 1800
}

5. Specify Codat API key in Monite partner settings

Next, you need to specify your encoded Codat API key in your partner settings in Monite. To do this, call PATCH /settings and provide the accounting object containing the encoded API key you obtained in step 1. The value is that of the Codat "Authorization header" but without the "Basic " prefix.

curl -X PATCH 'https://api.sandbox.monite.com/v1/settings' \
     -H 'X-Monite-Version: 2024-01-31' \
     -H 'Authorization: Bearer YOUR_PARTNER_TOKEN' \
     -H 'Content-Type: application/json' \
     -d '{
       "accounting": {
         "provider": "codat",
         "token": "YOUR_ENCODED_CODAT_API_KEY"
       }
     }'

6. Set up entities in Monite

If you have not already, create entities in Monite that represent your customers. Since the connection to an accounting system is configured on the entity level, entities must already exist in Monite before you proceed further.

Entities who use Accounts Receivable also need to create their product catalog in Monite before setting up accounting connection.

7. Check if an entity already has an active accounting connection

Before configuring a new accounting connection for an entity, make sure this entity has no other existing accounting connections that are active at the moment. For this purpose, call GET /accounting_connections with the X-Monite-Entity-Id header containing the entity ID:

curl 'https://api.sandbox.monite.com/v1/accounting_connections' \
  -H 'X-Monite-Version: 2024-01-31' \
  -H 'X-Monite-Entity-Id: ENTITY_ID' \
  -H 'Authorization: YOUR_PARTNER_TOKEN'

If there are no other active connections set up for this entity, you will receive a 200 OK response with an empty data array:

{
  "data": []
}

8. Establish entity connection to an accounting system

To establish a new accounting connection that allows an entity to synchronize all its accounting data with a third-party accounting system, call POST /accounting_connections. In this request, pass the entity ID in the X-Monite-Entity-Id header and specify the software type in the platform parameter:

curl -X POST 'https://api.sandbox.monite.com/v1/accounting_connections' \
     -H 'X-Monite-Version: 2024-01-31' \
     -H 'X-Monite-Entity-Id: ENTITY_ID' \
     -H 'Authorization: Bearer YOUR_PARTNER_TOKEN' \
     -d '{
       "platform": "xero"
     }'

The successful 201 Created response contains the information about the newly created connection:

{
    "id": "bb0b61e3-2295-4212-8a96-df60dd3528ab",
    "created_at": "2023-02-16T07:38:01.631172+00:00",
    "updated_at": "2023-02-16T07:38:01.631192+00:00",
    "status": "pending_auth",
    "platform": "xero",
    "connection_url": "https://link-api.codat.io/companies/42ed7770-51ea-45e5-9e4a-160er3db539d/connections/70eb9b71-7126-4d5f-b088-de7b86c84bc5/start",
    "last_pull": "2023-02-16T07:38:01.631218+00:00",
    "errors": null
}

The status of a newly created accounting connection is pending_auth. This means that an entity user needs to authorize this connection by using a web page specified by the the connection_url field.

Note down the connection_url value as you will need it on the next step.

Make sure to also store the id of this connection, as you will need it later to retrieve the connection status and details via GET /accounting_connections/{id}.

9. Entity user authorizes their connection

Next, send the connection_url received on the previous step to the entity user who is responsible for authorizing the accounting integration. For example, if your application is web-based, you can redirect the user to that URL.

On this page, the entity user must provide their login credentials with that accounting system and give authorization for Monite to access their data via Codat.

The URL of this authorization page looks like this:

https://link-api.codat.io/companies/SOME_ID/connections/SOME_ID/start

The next steps vary depending on the accounting system, and below we give you an example of how this flow might look like for Xero.

Xero authorization flow

Xero authorization flow

  1. Log in to Xero (if not already).
  2. The following screen is displayed.
    Select the organization account whose data you want to synchronize, and click Allow access:
  1. On the next screen, verify the selected organization and click Confirm:
  1. On the next screen, click Next:
  1. Click Finish:

10. Configure invoice statuses to push into the accounting system (Optional)

By default, Monite pushes payables and receivables to the connected accounting system when they have these statuses:

  • Payable statuses: waiting_to_be_paid, paid, partially_paid - payables in the statuses paid and partially_paid will be pushed with their status set as waiting_to_be_paid.
  • Receivable statuses: issued, paid, partially_paid, overdue, canceled, uncollectible

Entities can change the status list if needed.

To set the statuses, call PATCH /accounting_sync_rules with the following request body, replacing the status list as needed:

curl -X PATCH 'https://api.sandbox.monite.com/v1/accounting_sync_rules' \
     -H 'X-Monite-Version: 2024-01-31' \
     -H 'X-Monite-Entity-Id: ENTITY_ID' \
     -H 'Authorization: Bearer YOUR_PARTNER_TOKEN' \
     -H 'Content-Type: application/json' \
     -d '{
       "push_statuses": {
         "payable": [
           "waiting_to_be_paid"
         ],
         "receivable": [
           "issued",
           "canceled",
           "overdue",
           "uncollectible",
           "partially_paid",
           "paid"
         ]
       }
     }'

To get the current list of pushable statuses, call GET /accounting_sync_rules.

11. Manage ledger accounts

A general ledger (GL) account is a component of an accounting system that is used to record and categorize a company's financial transactions. Some examples of common ledger accounts are:

  • Expenses: office supplies, utilities, salaries, taxes, and so on,
  • Income: sales and revenue, dividends, and so on,
  • Assets: cash, inventory, and so on,
  • Liabilities: accounts payable, debt, and so on.

Within an accounting system, each line item on an invoice is assigned a ledger account in order to properly categorize various expenses and income sources. In Monite, the ledger_account_id field of products and payable line items is used to assign ledger accounts to business objects.

Products and payables pulled from the accounting system have the ledger_account_id pre-filled. However, when new products and payables are created in Monite, the user must manually specify the ledger_account_id for those objects. This is required for Monite to be able to push invoices (both payables and receivables) to the accounting system.

The typical flow is as follows:

  1. After connecting an entity to an accounting system, wait until the initial data pull is completed.

  2. Call GET /ledger_accounts to get a list of an entity's general ledgers pulled from the accounting system.

  3. If an entity uses Accounts Payable:

    1. Get the line items of all payables and check if the line items have ledger_account_id.
    2. If any line item is missing a value for ledger_account_id, prompt the user to assign the appropriate ledger account.
  4. If an entity uses Accounts Receivable:

    1. Get all products and check if they have ledger_account_id.
    2. If any product is missing a value for ledger_account_id, prompt the user to assign the appropriate ledger account.

11.1. Get ledger accounts from the accounting system

Ledger accounts cannot be created in Monite and can only be pulled from an accounting system.

After connecting to an accounting system, Monite automatically retrieves a list of ledger accounts from there. Once the initial data synchronization has completed, you can call GET /ledger_accounts to get an entity's ledger accounts that exist in the accounting system:

curl 'https://api.sandbox.monite.com/v1/ledger_accounts' \
  -H 'X-Monite-Version: 2024-01-31' \
  -H 'X-Monite-Entity-Id: ENTITY_ID' \
  -H 'Authorization: Bearer ACCESS_TOKEN'

Below is an example of ledger account details. Note down the IDs of the ledger accounts - these are the possible values of the ledger_account_id field in products and payable line items.

{
  "data": [
    {
      "id": "f5f85999-cc35-43e6-93ad-46d22907022a",
      "currency": "EUR",
      "current_balance": 0,
      "description": "Outstanding invoices the company has issued out to the client but has not yet received in cash at balance date.",
      "is_bank_account": false,
      "name": "Accounts Receivable",
      "nominal_code": "610",
      "status": "Active",
      "subtype": "Current",
      "type": "Asset"
    },
    {
      "id": "8ecb60fd-88fd-40e4-8bd9-5fa154435b78",
      "currency": "EUR",
      "current_balance": 0,
      "description": "Income from business activity",
      "is_bank_account": false,
      "name": "Sales",
      "nominal_code": "200",
      "type": "Income",
      "status": "Active",
      "subtype": "Revenue"
    },
    ...
  ],
  "next_pagination_token": null,
  "prev_pagination_token": null
}

11.2. Assign ledger accounts to products and payable line items

Before payables can be pushed to an accounting system, each line item in all payables must have the ledger_account_id specified. Similarly, before Account Receivable invoices can be pushed to accounting, all products listed on invoices must have the ledger_account_id specified.

To specify an associated ledger account for a payable line item or a product, PATCH this object and provide the value for ledger_account_id. For example:

curl -X PATCH 'https://api.sandbox.monite.com/v1/products/51846...39d' \
     -H 'X-Monite-Version: 2024-01-31' \
     -H 'X-Monite-Entity-Id: ENTITY_ID' \
     -H 'Authorization: Bearer ACCESS_TOKEN' \
     -H 'Content-Type: application/json' \
     -d '{
       "ledger_account_id": "f5f85999-cc35-43e6-93ad-46d22907022a"
     }'

Disconnect the accounting system

To disconnect an already established accounting connection, call POST /accounting_connections/{id}/disconnect:

curl -X POST 'https://api.sandbox.monite.com/v1/accounting_connections/{id}/disconnect' \
  -H 'X-Monite-Version: 2024-01-31' \
  -H 'X-Monite-Entity-Id: ENTITY_ID' \
  -H 'Authorization: Bearer YOUR_PARTNER_TOKEN'

The successful 200 OK response contains "status": "disconnected":

{
  "id": "3fa85f64-5717-4562-b3fc-2c963f76afa6",
  "status": "disconnected",
  "platform": "xero",
  "created_at": "2023-04-02T13:11:53.250Z",
  "updated_at": "2023-04-02T13:11:53.250Z",
  "last_pull": "2023-04-02T13:11:53.250Z",
  "errors": null
}

Troubleshooting

If you experience any issues and need our assistance with this integration, please feel free to contact our Support Team at any time.

Check the synchronization log

You can obtain an overview of all the synchronization events between Monite and the accounting system in a list. When the synchronization is successful, the status and IDs of records from both systems will be returned. If not, an error status with details will be returned instead.

To get a list with all the sync records, call GET /accounting_synced_records. Filtering the results by the object_type is mandatory. For example, GET /accounting_synced_records?object_type=bill will get all the sync records for bills (payables).

You can sort and filter the results by other fields. For the full list of available sort and filter parameters, see the GET /accounting_synced_records endpoint:

curl -X GET 'https://api.sandbox.monite.com/v1/accounting_synced_records?object_type=bill' \
  -H 'X-Monite-Version: 2024-01-31' \
  -H 'X-Monite-Entity-Id: ENTITY_ID' \
  -H 'Authorization: Bearer YOUR_PARTNER_TOKEN' \
{
  "data": [
    {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "created_at": "2024-03-05T15:14:14.728Z",
      "updated_at": "2024-03-05T15:14:14.728Z",
      "errors": {},
      "last_pulled_at": "2024-03-05T15:14:14.728Z",
      "object_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "object_type": "product",
      "object_updated_at": "2024-03-05T15:14:14.728Z",
      "platform": "xero",
      "platform_object_id": "18cb53c4-3807-4a5a-8da9-303053a40002",
      "platform_updated_at": "2024-03-05T15:14:14.728Z",
      "provider": "codat",
      "provider_object_id": "58e1d32f-a092-438a-bffb-3bf6af9ba8ec",
      "provider_updated_at": "2024-03-05T15:14:14.728Z",
      "sync_status": "pending"
    }
  ],
  "next_pagination_token": "eyJvcmRlciI6ImFzYyIsImxpbWl0IjoyLCJwYWdpbmF0aW9uX2ZpbHRlcnMiOnsiZW50aXR5X2lkIjoiOWQyYjRjOGYtMjA4Ny00NzM4LWJhOTEtNzM1OTY4M2M0OWE0In0sInBhZ2luYXRpb25fdG9rZW5fdHlwZSI6Im5leHQiLCJjdXJzb3JfZmllbGQiOm51bGwsImN1cnNvcl9maWVsZF92YWx1ZSI6bnVsbCwiY3VycmVudF9vaWQiOjR9",
  "prev_pagination_token": "eyJvcmRlciI6ImFzYyIsImxpbWl0IjoyLCJwYWdpbmF0aW9uX2ZpbHRlcnMiOnsiZW50aXR5X2lkIjoiOWQyYjRjOGYtMjA4Ny00NzM4LWJhOTEtNzM1OTY4M2M0OWE0In0sInBhZ2luYXRpb25fdG9rZW5fdHlwZSI6Im5leHQiLCJjdXJzb3JfZmllbGQiOm51bGwsImN1cnNvcl9maWVsZF92YWx1ZSI6bnVsbCwiY3VycmVudF9vaWQiOjR9"
}

You can get the details about a specific record by calling GET /accounting_synced_records/{synced_record_id}.

Retry pushing data

You can manually retry a failed sync to the accounting system in cases where errors occur during the attempt by calling POST /accounting_synced_records/{synced_record_id}/push. The synced_record_id of the failed sync can be obtained in the synchronization log:

curl -X POST 'https://api.sandbox.monite.com/v1/accounting_synced_records/{synced_record_id}/push' \
  -H 'X-Monite-Version: 2024-01-31' \
  -H 'X-Monite-Entity-Id: ENTITY_ID' \
  -H 'Authorization: Bearer YOUR_PARTNER_TOKEN' \
  -d ''

The successful response returns the information of the retried sync:

{
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "created_at": "2024-03-05T16:20:57.066Z",
  "updated_at": "2024-03-05T16:20:57.066Z",
  "errors": {},
  "last_pulled_at": "2024-03-05T16:20:57.066Z",
  "object_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "object_type": "product",
  "object_updated_at": "2024-03-05T16:20:57.066Z",
  "platform": "xero",
  "platform_object_id": "18cb53c4-3807-4a5a-8da9-303053a40002",
  "platform_updated_at": "2024-03-05T16:20:57.066Z",
  "provider": "codat",
  "provider_object_id": "58e1d32f-a092-438a-bffb-3bf6af9ba8ec",
  "provider_updated_at": "2024-03-05T16:20:57.066Z",
  "sync_status": "pending"
}

External resources

Codat documentation contains some helpful information about implementing and testing your accounting integrations: