Sync clients and sites into your system
By the end of this guide you will have a local copy of your agency’s clients and their sites, and a defensible way of keeping it current.
Before you start
Section titled “Before you start”- A client-credentials access token — see the Quickstart.
- Somewhere to store the records, keyed on the ids the API returns.
- A read of Multi-tenancy: what you get back is scoped to your agency and narrowed to the accessible branches of the user your API app acts as.
1. Decide between one call and two
Section titled “1. Decide between one call and two”Clients and sites can be fetched together or separately, and the right choice depends on your shape.
- Together — the combined listing returns each client with its sites nested, which is one pass and no correlation work. Use it for a full sync.
- Separately — list clients, then list the sites under a given client. Use it when you only need sites for a subset, or when the combined payload is larger than you want to hold.
Start with the combined call. Move to the split only if payload size becomes a real problem.
2. Page through the whole set
Section titled “2. Page through the whole set”List endpoints for clients and sites are paged, and the envelope is the same one described in Responses and pagination:
GET /v1/clients/with-sites?pageNumber=1&pageSize=100Authorization: Bearer {accessToken}pageSize is capped at 100 — asking for more silently gives you 100, so do not assume your requested
size was honoured. Loop until nextPage is null rather than computing the page count yourself; that
way a record added mid-sync does not truncate your run.
Both listings also accept a name filter, a branch filter, a client status filter and sort
parameters. Use them to narrow a sync, not to paginate — filtering is not a substitute for following
nextPage.
3. Store the ids, not your own keys
Section titled “3. Store the ids, not your own keys”Key your local records on the ids the API returns. They are opaque, they are the only way to fetch a record again, and they are the only thing that will still match on the next run — see Identifiers, audit and timestamps.
Store modifiedOn alongside each record. You will need it in the next step, and it is a UK-local
timestamp rather than UTC.
4. Re-sync by comparing, not by asking for changes
Section titled “4. Re-sync by comparing, not by asking for changes”This is the part that surprises people, so plan for it rather than looking for the endpoint that does not exist.
There is no incremental feed. No list endpoint takes a modified-since parameter, and there are no webhooks. A refresh means reading the set again and diffing it against what you hold.
That is workable because these sets are small and change slowly. A practical pattern:
- Read the full set on a schedule that matches how fast your agency’s client list actually moves — nightly is usually generous.
- Compare each record’s
modifiedOnagainst your stored value, and update only what moved. - Treat an id that is present locally but absent from the fresh read as removed or no longer visible — not necessarily deleted. A record can also leave your view because it was soft-deleted or because branch access changed. Mark it inactive rather than destroying your copy.
Verify the outcome
Section titled “Verify the outcome”- The number of clients you stored equals
totalCountfrom the first page of the run. - Re-running the sync immediately changes nothing — every
modifiedOnmatches. - A client you edit in the Recruso UI shows a newer
modifiedOnon the next run.
Failure modes
Section titled “Failure modes”| What you see | Why | What to do |
|---|---|---|
| Fewer records than colleagues see in the UI | The listing is narrowed to the accessible branches of the user behind your API app | Check that user’s branch access in the Recruso UI |
pageSize=500 returns 100 records |
The cap is 100 | Follow nextPage rather than requesting large pages |
| A 404 fetching a client whose id you hold | It was soft-deleted, or it left your branch access | Mark it inactive locally; do not delete the id |
| Timestamps an hour out for half the year | modifiedOn is UK local time and was parsed as UTC |
Parse as Europe/London |
| A 401 partway through a long run | The access token expired mid-sync | Re-authenticate and resume from the current page |
Work with agency lookups — the configuration data these records refer to by id.

