> ## Documentation Index
> Fetch the complete documentation index at: https://platform.doodocs.kz/llms.txt
> Use this file to discover all available pages before exploring further.

# Синхронизировать всех сотрудников

> Первичная выгрузка, инкрементальный опрос и сверка удалений

Цель — держать локальную копию справочника сотрудников ТОО «Керуен» в актуальном
состоянии. Схема простая: один раз выгрузите всех, дальше забирайте только
изменения, а удаления сверяйте периодическим полным перечитом.

<Note>
  Всё ниже требует области `employees:read`. Ключ видит только тех сотрудников и те
  поля, которые доступны профилю прав его владельца — эффективный доступ есть
  пересечение областей ключа и прав владельца.
</Note>

<Steps>
  <Step title="Первичная выгрузка">
    Пройдите список постранично с максимальным `limit=1000`, следуя за
    `next_page_token`, пока он не придёт пустым. В `expand` перечислите связанные
    сущности, которые нужны сразу — так вы не будете дёргать граф отдельными
    запросами.

    ```bash theme={null}
    curl -H "X-API-Key: ddp_ВАШ_КЛЮЧ" \
      "https://app.doodocs.kz/api/developer/v1/employees?limit=1000&expand=person&expand=department&expand=job_title"
    ```

    ```json Ответ theme={null}
    {
      "employees": [
        {
          "id": "3f2a9c7e-…",
          "employee_number": "R-0042",
          "status": "EMPLOYEE_STATUS_ACTIVE",
          "department_id": "d1…",
          "job_title_id": "j5…",
          "work_email": "kulyash@keruen.kz",
          "update_time": "2026-02-10T09:00:00Z",
          "redacted_fields": [],
          "person": { "display_name": "Куляш Байсеитова" }
        }
      ],
      "next_page_token": "CgYIyAE.7f3a"
    }
    ```

    Передавайте полученный `next_page_token` в следующий запрос — и так до пустого
    токена. Каждую запись сохраняйте по `id` (upsert).

    ```python theme={null}
    import requests

    BASE = "https://app.doodocs.kz/api/developer/v1"
    HEADERS = {"X-API-Key": "ddp_ВАШ_КЛЮЧ"}
    params = {"limit": 1000, "expand": ["person", "department", "job_title"]}

    token = None
    while True:
        page = {**params, **({"page_token": token} if token else {})}
        data = requests.get(f"{BASE}/employees", headers=HEADERS, params=page).json()
        for emp in data["employees"]:
            upsert(emp)                       # сохраните по emp["id"]
        token = data["next_page_token"]
        if not token:
            break
    ```

    <Warning>
      Токен привязан к набору фильтров, для которого был выдан. Если передать его в
      запрос с другими `status`, `department_id`, `updated_since` или `limit`, ответ
      будет `INVALID_ARGUMENT`. Меняете фильтры — начинайте обход заново без токена.
    </Warning>
  </Step>

  <Step title="Инкрементальный опрос">
    Запомните момент, когда начали синхронизацию (UTC), и сохраните его как
    чекпойнт. В следующий раз запрашивайте только то, что изменилось с чекпойнта,
    через `updated_since` (RFC 3339), а затем сдвиньте чекпойнт на время нового
    запуска.

    ```bash theme={null}
    curl -H "X-API-Key: ddp_ВАШ_КЛЮЧ" \
      "https://app.doodocs.kz/api/developer/v1/employees?updated_since=2026-02-10T09:00:00Z&limit=1000"
    ```

    Обход страниц — тот же, что и при полной выгрузке: идите за `next_page_token`
    до пустого токена. Берите чекпойнт от *начала* прогона, а не от конца, чтобы не
    потерять изменения, случившиеся во время обхода.

    Что попадает под `updated_since`, а что нет:

    | Изменение                                                                  | Двигает `updated_since`? | Как ловить                |
    | -------------------------------------------------------------------------- | :----------------------: | ------------------------- |
    | Поля самой карточки (`status`, `department_id`, `work_email`, `end_date`…) |            да            | `updated_since`           |
    | Переименование связанного человека (имя, ИИН, контакты)                    |            нет           | вебхук `employee.changed` |
    | Переименование отдела или должности                                        |            нет           | вебхук `employee.changed` |

    <Note>
      `updated_since` отражает изменения самой карточки сотрудника. Переименование
      связанных сущностей (человек, отдел, должность) в это поле **не** попадает —
      для них подпишитесь на [вебхуки](/ru/api-reference/webhooks): переименование
      человека приходит как `employee.changed` по каждому затронутому сотруднику.

      Смещение часового пояса в query кодируйте как `%2B05:00` или присылайте время
      в `Z` (UTC): «плюс» в URL иначе трактуется как пробел.
    </Note>
  </Step>

  <Step title="Сверка удалений">
    Инкрементальный опрос не сообщает об удалениях — удалённый сотрудник просто
    перестаёт появляться в списках, а `GET /employees/{id}` по нему возвращает
    `404` `EMPLOYEE_NOT_FOUND`. Поэтому периодически (например, раз в сутки) делайте
    полную выгрузку и вычитайте её из своего хранилища: чего нет в свежем полном
    списке — то удалено на стороне Doodocs, пометьте у себя.

    <Tip>
      Не путайте увольнение с удалением. Уволенный сотрудник остаётся в списках со
      статусом `EMPLOYEE_STATUS_TERMINATED` и заполненным `end_date` — его видно
      через обычный опрос. Удаление же убирает запись из выдачи полностью, и поймать
      его можно только полным перечитом или вебхуком `employee.deleted`.
    </Tip>
  </Step>
</Steps>

## Итоговый цикл

* **Один раз:** полная постраничная выгрузка → наполняете хранилище.
* **Часто (минуты):** `updated_since` от чекпойнта → upsert изменённых карточек.
* **Редко (раз в сутки):** полный перечит → сверка и пометка удалённых.
* **Мгновенно:** вебхуки `employee.changed` / `employee.deleted` закрывают то, что
  опрос по `updated_since` не видит (переименования связанных сущностей, удаления).

## Дальше

<Columns cols={2}>
  <Card title="Реагировать на приём и увольнение" icon="user-plus" href="/ru/guides/recipes/react-to-hire">
    Заменить опрос вебхуками и обрабатывать события в реальном времени.
  </Card>

  <Card title="Вебхуки" icon="bolt" href="/ru/api-reference/webhooks">
    Подписка, тонкий payload и проверка подписи.
  </Card>
</Columns>
