Skip to main content
This how-to covers the write operations for Chart of Accounts Sync: creating new Accounts, updating or unarchiving existing Accounts, and archiving Accounts that are no longer active in the Accounting System. Run this after How to Sync Accounts, which covers fetching and matching accounts from both systems.

Prerequisites

Before you begin:

Scenario

This how-to continues from the How to Sync Accounts scenario. After matching, the following actions are required:
AS AccountPleo AccountAction
1000 - Office Supplies1000 - Office SuppliesNo action
2000 - Travel2000 - TravelUnarchive
3000 - SoftwareCreate
4000 - Marketing4000 - AdvertisingUpdate
5000 - EntertainmentArchive
The diagram below shows where these operations fit in the full reconciliation loop.

Steps

1. Create Accounts for New AS Entries

API Endpoint: POST /v1/chart-of-accounts If an AS account has no matching Pleo Account, create a new Account. Example Pseudo:
if matchedAccount is null:
    newAccount.externalId = account.externalId
    newAccount.code       = account.code
    newAccount.name       = account.name
    newAccount.archived   = false
    POST newAccount to Pleo

Example Request

curl -X POST "https://external.staging.pleo.io/v1/chart-of-accounts" \
  -H "Authorization: Bearer <access_token>" \
  -H "Content-Type: application/json" \
  -d '{
        "companyId": "12abc3d4-e567-890e-1234-abc56e78fabc",
        "externalId": "ext-3000",
        "code": "3000",
        "name": "Software",
        "archived": false
      }'

Example Response

{
  "data": {
    "id": "e5f6g7h8-i901-234i-5678-efg90i12defg",
    "companyId": "12abc3d4-e567-890e-1234-abc56e78fabc",
    "externalId": "ext-3000",
    "code": "3000",
    "name": "Software",
    "archived": false
  }
}

What it looks like in Pleo Web App

Active Accounts with Software created


2. Unarchive or Update Existing Accounts

API Endpoint: PUT /v1/chart-of-accounts/{accountId} If a matching Account is found:
  • AS account is active, Pleo Account is archived: Unarchive by setting archived: false and update name and code if they differ.
  • AS account is active, Pleo Account name or code differs: Update the Account to match the AS.
  • AS account is active, Pleo Account name and code match: No action required.
Example Pseudo:
if matchedAccount.archived == true:
    matchedAccount.archived = false
    matchedAccount.name     = account.name
    matchedAccount.code     = account.code
    PUT matchedAccount to Pleo

else if matchedAccount.name != account.name or matchedAccount.code != account.code:
    matchedAccount.name = account.name
    matchedAccount.code = account.code
    PUT matchedAccount to Pleo

Unarchive

Example Request

The “2000 - Travel” Account is unarchived in this example.
curl -X PUT "https://external.staging.pleo.io/v1/chart-of-accounts/d8371c2d-3f62-47df-a8d6-6a3ba6387e00" \
  -H "Authorization: Bearer <access_token>" \
  -H "Content-Type: application/json" \
  -d '{
        "externalId": "ext-2000",
        "code": "2000",
        "name": "Travel",
        "archived": false
      }'

Example Response

{
  "data": {
    "id": "d8371c2d-3f62-47df-a8d6-6a3ba6387e00",
    "companyId": "12abc3d4-e567-890e-1234-abc56e78fabc",
    "externalId": "ext-2000",
    "code": "2000",
    "name": "Travel",
    "archived": false
  }
}

What it looks like in Pleo Web App

Active Accounts with Travel unarachived

Archived Accounts Empty

Update

Example Request

The “4000 - Advertising” Account is renamed to “4000 - Marketing” to match the AS in this example.
curl -X PUT "https://external.staging.pleo.io/v1/chart-of-accounts/a470bfbe-8046-4b43-a4d9-4f5796acdd93" \
  -H "Authorization: Bearer <access_token>" \
  -H "Content-Type: application/json" \
  -d '{
        "externalId": "ext-4000",
        "code": "4000",
        "name": "Marketing",
        "archived": false
      }'

Example Response

{
  "data": {
    "id": "a470bfbe-8046-4b43-a4d9-4f5796acdd93",
    "companyId": "12abc3d4-e567-890e-1234-abc56e78fabc",
    "externalId": "ext-4000",
    "code": "4000",
    "name": "Marketing",
    "archived": false
  }
}

What it looks like in Pleo Web App

Before update:
Active Accounts showing 4000 - Advertising

After Update:
Active Accounts showing 4000 - Marketing

3. Archive Accounts with No Matching AS Entry

API Endpoint: PUT /v1/chart-of-accounts/{accountId} If a Pleo Account is active but its corresponding AS account is no longer active (or does not exist), archive the Account. Do not delete Accounts. Archiving is non-destructive and reversible. Example Pseudo:
activeASExternalIds = activeASAccounts.map(a => a.externalId)

for account in pleoAccounts where archived == false:
    if account.externalId not in activeASExternalIds:
        account.archived = true
        PUT account to Pleo

Example Request

curl -X PUT "https://external.staging.pleo.io/v1/chart-of-accounts/7ea2006f-180e-4c52-a2bb-562d3a62fd48" \
  -H "Authorization: Bearer <access_token>" \
  -H "Content-Type: application/json" \
  -d '{
        "externalId": "5000",
        "code": "5000",
        "name": "Entertainment",
        "archived": true
      }'

Example Response

{
  "data": {
    "id": "7ea2006f-180e-4c52-a2bb-562d3a62fd48",
    "companyId": "12abc3d4-e567-890e-1234-abc56e78fabc",
    "externalId": "5000",
    "code": "5000",
    "name": "Entertainment",
    "archived": true
  }
}

What it looks like in Pleo Web App

Archive Accounts showing that Entertainment is not longer part of the list

Archive Accounts showing that Entertainment was archived

Result

The table below recaps what happened to each Account across all steps.
AccountAS StatusPleo State BeforeActionFinal Pleo State
1000 - Office SuppliesActiveActive, matchesNo actionActive
2000 - TravelActiveArchivedUnarchivedActive
3000 - SoftwareActiveDoes not existCreatedActive
4000 - MarketingActiveActive, name differedUpdatedActive
5000 - EntertainmentNot in ASActiveArchivedArchived
Pleo now reflects the current Chart of Accounts from the AS.
AccountFinal State in PleoIn AS?Aligned?
1000 - Office SuppliesActiveYes✓ Yes
2000 - TravelActiveYes✓ Yes
3000 - SoftwareActiveYes✓ Yes
4000 - MarketingActiveYes✓ Yes
5000 - EntertainmentArchivedNo✓ Yes

What Comes Next?


this how-to is part of: