Skip to main content
The goal is to keep a local copy of the Keruen LLP employee directory up to date. The scheme is simple: export everyone once, then fetch only changes, and reconcile deletions with a periodic full re-read.
Everything below requires the employees:read scope. The key sees only the employees and fields available to the owner’s permission profile — effective access is the intersection of the key’s scopes and the owner’s permissions.
1

Initial export

Walk the list page by page with the maximum limit=1000, following next_page_token until it comes back empty. In expand, list the related entities you need up front — that way you avoid hitting the graph with separate requests.
Response
Pass the returned next_page_token into the next request — and so on until the token is empty. Save each record by id (upsert).
A token is bound to the filter set it was issued for. Passing it into a request with different status, department_id, updated_since, or limit returns INVALID_ARGUMENT. When you change filters, start the walk again without a token.
2

Incremental polling

Remember the moment you started the sync (UTC) and store it as a checkpoint. Next time, request only what changed since the checkpoint via updated_since (RFC 3339), then advance the checkpoint to the time of the new run.
Paging is the same as for a full export: follow next_page_token until the token is empty. Take the checkpoint from the start of the run, not the end, so you do not lose changes that happened during the walk.What updated_since covers and what it does not:
updated_since reflects changes to the employee record itself. Renaming related entities (person, department, job title) does not land in this field — for those, subscribe to webhooks: a person rename arrives as employee.changed for each affected employee.Encode the timezone offset in the query as %2B05:00, or send the time in Z (UTC): a “plus” in a URL is otherwise interpreted as a space.
3

Reconcile deletions

Incremental polling does not report deletions — a deleted employee simply stops appearing in lists, and GET /employees/{id} for it returns 404 EMPLOYEE_NOT_FOUND. So periodically (for example, once a day) do a full export and subtract it from your store: anything not in the fresh full list has been deleted on the Doodocs side — mark it in your store.
Do not confuse termination with deletion. A terminated employee stays in the lists with status EMPLOYEE_STATUS_TERMINATED and a filled-in end_date — it is visible through normal polling. Deletion, on the other hand, removes the record from the output entirely, and you can only catch it with a full re-read or the employee.deleted webhook.

The resulting cycle

  • Once: a full paged export → you fill the store.
  • Often (minutes): updated_since from the checkpoint → upsert the changed records.
  • Rarely (once a day): a full re-read → reconcile and mark deletions.
  • Instantly: the employee.changed / employee.deleted webhooks cover what polling by updated_since does not see (renames of related entities, deletions).

Next

React to hire and termination

Replace polling with webhooks and handle events in real time.

Webhooks

Subscribing, the thin payload, and signature verification.