entityKey is the id you store. It does not change when a lead becomes an Active client, and it is the foreign key for contacts, eForms, proposals, bills, and onboardings.
This guide is the read path. Creating a client is at the end. Creating a lead with a source, status, and opening note is Leads and deals.
Before you call
- Use the practice region for every request. There is no cross-region routing. See Regions.
- Call
GET /api/v1/auth/validateonce during setup. ReadcanWrite. Listing clients works with read-only credentials.POST /api/v1/entitiesdoes not. - Store three identifiers per client:
Full import
GET /api/v1/entities/list is paged. pageNumber is 1-based, up to 10000. Keep requesting the next page until the page is empty.
fullEntityName,entityEmail,entityMobile,entityTelephoneentityType(the practice’s type name, such as Individual or Company)entityTerminatedpartnerName,managerName,inChargeName(display names, not user keys)updatedOn(UTC). This is the value you compare with your watermark.
name, otherName, surname, email. Use them for a lookup, not for the full import.
List does not return addresses or integration ids. Load those per client, below, and only for the clients you actually map.
Detail, then integrations
GET /api/v1/entities/{key} is the full client: addresses, tax and registration numbers, and custom field values that are populated.
GET /api/v1/entities/{key}/integrations is the cross-system map. A null or empty id means that product is not linked for this client.
Match on these ids when your product already has the client. Match on
externalSystemID when you created the client from your system.
People on the client
Contacts are a separate object. A contact is a person tied to oneentityKey.
- Full sync:
GET /api/v1/contacts/listwithpageNumber, thenlastUpdated. - One client:
GET /api/v1/entities/{entityKey}/contacts, orGET /api/v1/contacts/list?entityKey=. - Soft-deleted contacts are hidden unless
includeDeleted=true.
POST and PUT on /api/v1/entities/{entityKey}/contacts).
Incremental sync
After the first import, store the greatestupdatedOn you successfully persisted, in UTC. Next run:
- Send UTC. A future timestamp is rejected.
- Do not move the watermark forward until every page of that run is stored. A crash mid-page should retry the same
lastUpdated. - The same pattern works on contacts, leads, deals, groups, and users. Bills do not use
lastUpdated. They filter on bill date. See Bills. lastUpdatedreturns rows changed on or after that time. Overlap by a minute if your clock and ours can disagree, and upsert onentityKey.
Create a client
POST /api/v1/entities needs canWrite: true.
GET /api/v1/settings/entity-typesand sendentityTypeas the code or display name (Company,Individual,Trust).entityTypeIDis the numeric alternative. If both are sent,entityTypewins.clientStatusisActivefor a client you can bill and propose to, orLeadif they are not a client yet. For a real lead (source, status, value, opening note) usePOST /api/v1/leadsinstead.- Naming depends on type. Individuals and sole traders:
entityNameis the given name andentitySurnameis the family name. They are not split for you. Companies:entityNameis the legal or trading name, andentitySurnamestays unset. - Send
externalSystemIDif you want the client to round-trip to your id on later list and get calls.
entityKey immediately. That is the id for every later call.
What usually goes wrong
Endpoint reference
List, get, create, integrations, and the contact routes.