Skip to content

Синхронизация и постраничность ​

Оба списочных метода устроены одинаково: страница по курсору плюс необязательный фильтр «что изменилось после».

json
{
  "items": [ /* ... */ ],
  "nextCursor": "MjAyNi0wOC0wMVQxMjowMDowMC4wMDBafGNseDEyMw"
}

nextCursor равен null, когда страница последняя. Пока он не null — идите дальше, подставляя его в параметр cursor.

Почему курсор, а не смещение ​

Параметра offset здесь нет намеренно. Пока вы идёте по страницам, данные меняются: вакансию правят, кандидат переезжает по доске. Со смещением это означает, что часть записей вы получите дважды, а часть не получите вовсе — и узнаете об этом не сразу.

Курсор указывает на позицию в сортировке, а не на номер строки, и от вставок не страдает.

Параметры ​

ПараметрЗначение
limitразмер страницы, 1..500, по умолчанию 100
cursorкурсор из nextCursor предыдущей страницы
sinceISO 8601; вернутся записи, изменённые после этого момента

Инкрементальная синхронизация ​

since сравнивается с отметкой правки, а не создания. Это важнее, чем кажется: без этого закрытая вакансия никогда не доехала бы до вас, и портал показывал бы людям позицию, на которую уже не берут.

У кандидатов сравнение идёт по двум отметкам сразу — по самой карточке и по её резюме. Резюме живёт отдельно и обновляется при переимпорте с hh.ru; без второй отметки обновлённое резюме осталось бы у нас.

Схема регулярной синхронизации:

bash
SINCE=$(cat .last-sync)          # отметка предыдущего успешного прохода
NOW=$(date -u +%Y-%m-%dT%H:%M:%SZ)

CURSOR=""
while :; do
  RESP=$(curl -s -H "X-API-Key: $KEY" \
    "$BASE/vacancies?status=all&since=$SINCE&limit=200${CURSOR:+&cursor=$CURSOR}")
  echo "$RESP" | jq -c '.items[]' >> vacancies.ndjson
  CURSOR=$(echo "$RESP" | jq -r '.nextCursor // empty')
  [ -z "$CURSOR" ] && break
done

echo "$NOW" > .last-sync         # отметку берём ДО прохода, а не после

Отметку следующего прохода берите до начала выгрузки, а не после её окончания: запись, изменившаяся во время обхода, иначе потеряется.

Первая синхронизация вытянет всё ​

Отметка правки появилась в платформе вместе с этим API, и существующим записям она проставлена моментом обновления. Поэтому первый проход с since вернёт всю базу целиком — один раз. Дальше объёмы будут обычными.

Удаления не приходят ​

Удалённая запись просто перестаёт появляться в выдаче — отдельного признака «удалено» в API нет.

Если вам важно не показывать то, чего у нас больше нет, раз в сутки делайте полный проход без since и сверяйте множество идентификаторов. Вакансий обычно сотни, такой проход стоит недорого.

Архив — другое дело: снятая вакансия приходит штатно, со статусом archived, и по ней видно, что позиция закрыта.