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.
Data | Pulled | Pushed |
---|---|---|
Ledger accounts | References to ledger accounts in invoice line items, and products | |
Counterparts | ||
Products | ||
Accounts Receivable: invoices | ||
Accounts Payable: invoices (bills) |
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 term | Codat term |
---|---|
Entity | Company |
Entity user | n/a |
Counterpart | Customer, Supplier |
Payable | Bill |
Receivable: Invoice | Invoice |
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:
- Log in the Codat Portal.
- In the top right corner, select the Codat client account whose API key you need - Test instance or Production instance.
- Go to Developers > API > API keys.
- If you don't already have an API key, create one.
- Copy the value of the Authorization header (not the API key value). This value is in the format
Basic YOUR_ENCODED_API_KEY
.
- 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:
- Sandbox environment: https://api.sandbox.monite.com/v1/webhooks/codat
- Production environment: https://api.monite.com/v1/webhooks/codat
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:
- In the Codat Portal, select your Codat client account to configure webhooks for - Test instance or Production instance.
- Go to Settings > Webhooks > Rules.
- Click Create new rule.
- 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:
- If configuring webhooks for Codat Test instance, specify:
https://api.sandbox.monite.com/v1/webhooks/codat - If configuring webhooks for Codat Production instance, specify:
https://api.monite.com/v1/webhooks/codat
- If configuring webhooks for Codat Test instance, specify:
- 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
- Log in to Xero (if not already).
- The following screen is displayed.
Select the organization account whose data you want to synchronize, and click Allow access:
- On the next screen, verify the selected organization and click Confirm:
- On the next screen, click Next:
- 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 statusespaid
andpartially_paid
will be pushed with their status set aswaiting_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:
-
After connecting an entity to an accounting system, wait until the initial data pull is completed.
-
Call
GET /ledger_accounts
to get a list of an entity's general ledgers pulled from the accounting system. -
If an entity uses Accounts Payable:
- Get the line items of all payables and check if the line items have
ledger_account_id
. - If any line item is missing a value for
ledger_account_id
, prompt the user to assign the appropriate ledger account.
- Get the line items of all payables and check if the line items have
-
If an entity uses Accounts Receivable:
- Get all products and check if they have
ledger_account_id
. - If any product is missing a value for
ledger_account_id
, prompt the user to assign the appropriate ledger account.
- Get all products and check if they have
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:
Updated about 1 month ago