Skip to main content
This how-to covers the fetch and match phase of Chart of Accounts Sync: retrieving accounts from the Accounting System and Pleo, then determining what action is needed for each. For the write operations, see How to Create, Update, and Archive Accounts. Your integration must:
  • Retrieve active accounts from the AS
  • Retrieve all Accounts (active and archived) from Pleo
  • Match AS accounts to Pleo Accounts by externalId to determine what action is needed

Prerequisites

Before you begin:

Scenario

This how-to uses a consistent example to illustrate each step. The table below shows the starting state in both systems before this sync runs.
Account (AS)externalIdAS StatusAccount (Pleo)Pleo Status
1000 - Office Suppliesext-1000Active1000 - Office SuppliesActive
2000 - Travelext-2000Active2000 - TravelArchived
3000 - Softwareext-3000ActiveDoes not exist
4000 - Marketingext-4000Active4000 - AdvertisingActive
50005000 - EntertainmentActive

Steps

1. Retrieve Active Accounts from the Accounting System

Fetch all active accounts from the Chart of Accounts in the AS. Example Pseudo:
activeASAccounts = fetchActiveAccountsFromAS()

Example Result

AccountexternalIdAS Status
1000 - Office Suppliesext-1000Active
2000 - Travelext-2000Active
3000 - Softwareext-3000Active
4000 - Marketingext-4000Active

2. Retrieve All Accounts from Pleo

API Endpoint: POST /v1/chart-of-accounts:search Example parameters:
  • companyId: 12abc3d4-e567-890e-1234-abc56e78fabc
  • includeArchived: true
Fetch both active and archived Accounts from Pleo. Including archived Accounts allows unarchiving rather than creating duplicates. Example Pseudo:
pleoAccounts = fetchAccountsFromPleo(includeArchived: true)

Example Request

curl -X POST "https://external.staging.pleo.io/v1/chart-of-accounts:search" \
  -H "Authorization: Bearer <access_token>" \
  -H "Content-Type: application/json" \
  -d '{
        "companyId": "12abc3d4-e567-890e-1234-abc56e78fabc",
        "includeArchived": true
      }'

Example Response

{
  "data": [
    {
      "id": "7ea2006f-180e-4c52-a2bb-562d3a62fd48",
      "companyId": "12abc3d4-e567-890e-1234-abc56e78fabc",
      "code": "5000",
      "externalId": "5000",
      "name": "Entertainment",
      "archived": false
    },
    {
      "id": "a470bfbe-8046-4b43-a4d9-4f5796acdd93",
      "companyId": "12abc3d4-e567-890e-1234-abc56e78fabc",
      "code": "4000",
      "externalId": "ext-4000",
      "name": "Advertising",
      "archived": false
    },
    {
      "id": "d8371c2d-3f62-47df-a8d6-6a3ba6387e00",
      "companyId": "12abc3d4-e567-890e-1234-abc56e78fabc",
      "code": "2000",
      "externalId": "ext-2000",
      "name": "Travel",
      "archived": true
    },
    {
      "id": "77049275-e102-4ce4-84e5-c90852765fcd",
      "companyId": "12abc3d4-e567-890e-1234-abc56e78fabc",
      "code": "1000",
      "externalId": "ext-1000",
      "name": "Office Supplies",
      "archived": false
    }
  ],
  "pagination": {
    "hasPreviousPage": false,
    "hasNextPage": false,
    "currentRequestPagination": {
      "sortingKeys": [],
      "sortingOrder": [],
      "parameters": {}
    },
    "startCursor": "AAAAAADKHEEOIDOJO34A=AAAAAADKHEEOIDOJO34A=P2RAA3YYBZGFFIV3KYWTUYX5JA",
    "endCursor": "AAAAAADKCVM2UIAPLIEA=AAAAAADKHEETOMBB2K4A=BLNKLWE6ZBBDLLU24XGZ4GAFAI",
    "total": 4
  }
}

Example Result

Account (Pleo)externalIdPleo Status
1000 - Office Suppliesext-1000Active
2000 - Travelext-2000Archived
4000 - Advertisingext-4000Active
5000 - Entertainment5000Active

What it looks like in Pleo Web App

Active Accounts Tab

Unarchived Accounts Tab

3. Match AS Accounts to Pleo Accounts by externalId

For each active AS account, attempt to find a matching Account in Pleo using externalId. Example Pseudo:
pleoAccountsByExternalId = index pleoAccounts by externalId

for account in activeASAccounts:
    matchedAccount = pleoAccountsByExternalId[account.externalId]

    if matchedAccount is null:
        createAccount(account)
    else if matchedAccount.archived == true:
        unarchiveAndUpdate(matchedAccount, account)
    else if matchedAccount.name != account.name or matchedAccount.code != account.code:
        updateAccount(matchedAccount, account)
    // else: no action needed

Example Result

AS AccountPleo AccountPleo StatusAction
1000 - Office Supplies1000 - Office SuppliesActive, matchesNo action
2000 - Travel2000 - TravelArchivedUnarchive
3000 - SoftwareDoes not existCreate
4000 - Marketing4000 - AdvertisingActive, differsUpdate
5000 - EntertainmentActiveArchive

What Comes Next?


this how-to is part of: