HeadHunter API (hh.ru) API

Отрасль: HR и рекрутинг. Актуально на 2026-10-24.

REST API сайтов группы HeadHunter (hh.ru, rabota.by, hh1.az, hh.uz, hh.kz, headhunter.ge, headhunter.kg). Позволяет искать вакансии, резюме и работодателей, публиковать и архивировать вакансии, работать с откликами и приглашениями, вести переписку в чатах, получать справочники и подписываться на вебхуки. Данные передаются только в JSON по HTTPS, даты — в формате ISO 8601 (YYYY-MM-DDThh:mm:ss±hhmm).

Сценарии

Найти вакансии по запросу

Поиск вакансий hh.ru для своего сайта, бота или аналитики зарплат.

  1. Передавай в каждом запросе заголовок HH-User-Agent с названием приложения и почтой разработчика — без него придёт 400.
  2. Узнай ID региона: GET /areas (1 — Москва, 2 — Санкт-Петербург). Значения фильтров (опыт, тип занятости, сортировка) — в GET /dictionaries.
  3. Ищи: GET /vacancies с text, area, salary, experience, per_page (до 100) и page (с нуля). Только с указанной зарплатой — label = with_salary.
  4. В ответе found, pages и items. Глубина выдачи — не больше 2000 вакансий: для полного охвата сужай запрос по регионам или датам (date_from, date_to).
  5. Без токена после первого запроса может потребоваться капча (ответ 403) — для массовых запросов используй токен приложения.
curl -G https://api.hh.ru/vacancies \
  -H 'HH-User-Agent: MyApp/1.0 (dev@example.ru)' \
  --data-urlencode 'text=python разработчик' \
  -d area=1 -d salary=200000 -d only_with_salary=true \
  -d per_page=50 -d page=0

Опубликовать вакансию от имени работодателя

Размещать вакансии из своей ATS или карьерного сайта сразу на hh.ru.

  1. Зарегистрируй приложение на dev.hh.ru. Отправь менеджера работодателя на https://hh.ru/oauth/authorize с response_type = code, client_id и redirect_uri.
  2. Обменяй код на токены: POST /token с grant_type = authorization_code, client_id, client_secret, code и redirect_uri (тело — form-urlencoded). Обновить пару — тот же метод с refresh_token, но только после истечения access_token.
  3. Узнай ID работодателя: GET /me — поле employer.id.
  4. Опубликуй: POST /vacancies с name, description (HTML), area, professional_roles и при необходимости salary_range, experience, work_format, key_skills. Ответ 201. Услуги списываются с пакета работодателя; все вакансии проходят модерацию и появляются в поиске через несколько минут.
  5. Изменить вакансию — PUT /vacancies/{vacancy_id} (составные поля вроде salary_range передавай целиком). Снять с публикации — PUT /employers/{employer_id}/vacancies/archived/{vacancy_id}.
curl -X POST https://api.hh.ru/vacancies \
  -H "Authorization: Bearer $HH_TOKEN" \
  -H 'HH-User-Agent: MyApp/1.0 (dev@example.ru)' \
  -H 'Content-Type: application/json' \
  -d '{
        "name": "Python-разработчик",
        "description": "<p>Разрабатываем сервисы для логистики.</p><ul><li>Python 3, FastAPI</li></ul>",
        "area": {"id": "1"},
        "professional_roles": [{"id": "96"}],
        "salary_range": {"from": 200000, "to": 300000, "currency": "RUR", "gross": false, "mode": {"id": "MONTH"}, "frequency": {"id": "TWICE_PER_MONTH"}},
        "key_skills": [{"name": "Python"}, {"name": "PostgreSQL"}]
      }'

Разобрать отклики на вакансию

Забирать откликнувшихся кандидатов в свою систему и приглашать или отказывать без захода на hh.ru.

  1. Получи отклики: GET /negotiations с vacancy_id (обязателен для работодателя) и, например, has_updates = true — только с непросмотренным.
  2. Открой отклик: GET /negotiations/{id} — адрес берётся из items[].url. Резюме кандидата смотри через ссылку из отклика.
  3. Чтобы пригласить или отказать, возьми из actions[] нужное действие и вызови PUT /negotiations/{collection_name}/{nid} с аргументами из actions[].arguments (form-urlencoded). Успех — 204.
  4. Не составляй адреса действий вручную: доступные действия зависят от состояния отклика и приходят в ответе.
curl -G https://api.hh.ru/negotiations \
  -H "Authorization: Bearer $HH_TOKEN" -H 'HH-User-Agent: MyApp/1.0 (dev@example.ru)' \
  -d vacancy_id=123456789 -d has_updates=true -d per_page=50

Переписываться с кандидатом в чате

Отправлять кандидатам сообщения из своей системы и читать ответы.

  1. Получи чаты: GET /common/chats — с filter_unread = true только непрочитанные, с filter_with_vacancy_ids — по нужным вакансиям.
  2. Прочитай сообщения: GET /common/chats/{chat_id}/messages с limit (до 50) и start_message_id для постраничного чтения.
  3. Отправь сообщение: POST /common/chats/{chat_id}/messages с idempotency_key (UUID) и text. Повтор с тем же ключом вернёт 409 и не создаст дубль.
  4. Старые методы /negotiations/{nid}/messages устарели — переписку веди через /common/chats.
curl -X POST https://api.hh.ru/common/chats/<chat_id>/messages \
  -H "Authorization: Bearer $HH_TOKEN" -H 'HH-User-Agent: MyApp/1.0 (dev@example.ru)' \
  -H 'Content-Type: application/json' \
  -d "{\"idempotency_key\": \"$(uuidgen)\", \"text\": \"Добрый день! Приглашаем на собеседование в четверг в 15:00.\"}"

Получать уведомления о новых откликах

Узнавать о новых откликах и сообщениях сразу, без опроса.

  1. Подпишись: POST /webhook/subscriptions с url своего обработчика и actions — списком нужных событий (типы событий — в документации вебхуков). Доступно только работодателю; на приложение — один URL.
  2. Колбэк приходит POST-запросом с action_type, id и payload (vacancy_id, resume_id, chat_id и др.). Отвечай 2xx в течение 5 секунд, на повтор с тем же id — 409.
  3. Доставка не гарантирована: раз в несколько часов сверяй отклики через GET /negotiations.
  4. Список подписок — GET /webhook/subscriptions, удалить — DELETE /webhook/subscriptions/{subscription_id}.
curl -X POST https://api.hh.ru/webhook/subscriptions \
  -H "Authorization: Bearer $HH_TOKEN" -H 'HH-User-Agent: MyApp/1.0 (dev@example.ru)' \
  -H 'Content-Type: application/json' \
  -d '{"url": "https://example.ru/hh/webhook", "actions": [{"type": "<тип события>"}]}'

Базовые URL

Авторизация

Тип: OAuth 2.0

OAuth 2.0. Токен передаётся в заголовке Authorization: Bearer {ACCESS_TOKEN}.

Параметры /oauth/authorize: skip_choose_account=true — не показывать выбор аккаунта, force_login=true — всегда показывать форму входа, role (applicant или employer) с force_role=true — требовать нужную роль.

В каждом запросе обязателен заголовок User-Agent или HH-User-Agent (при обоих учитывается HH-User-Agent); без него — 400 Bad Request.

User-Agent: MyApp/1.0 (my-app-feedback@example.com)

Методы

POST /token — Получение access-токена

Тело — application/x-www-form-urlencoded. Набор полей зависит от grant_type (получение токена пользователя, обновление пары токенов, токен приложения). Ниже — поля для обмена authorization_code.

В ответе: access_token, token_type (bearer), expires_in, refresh_token.

Параметр Где Тип Обяз. Описание
HH-User-Agent header string да Название приложения и почта разработчика
grant_type body string да authorization_code
client_id body string да Идентификатор приложения
client_secret body string да Секретный ключ приложения
code body string да Полученный authorization_code
redirect_uri body string да URI перенаправления (если не указан — из настроек приложения)
code_verifier body string нет Верификатор PKCE; обязателен, если передавался code_challenge

DELETE /token — Инвалидация токена

Работает только для действующего токена пользователя; токен приложения так инвалидировать нельзя. После инвалидации нужно авторизоваться заново. Успех — 204.

Параметр Где Тип Обяз. Описание
HH-User-Agent header string да Название приложения и почта разработчика

GET /me — Информация о текущем пользователе

В ответе: auth_type, id, email, first_name, last_name, is_applicant, is_employer, employer, manager, counters и др.

Параметр Где Тип Обяз. Описание
HH-User-Agent header string да Название приложения и почта разработчика

GET /vacancies — Поиск по вакансиям

Неизвестные параметры игнорируются. Без токена после первого запроса может потребоваться капча. Глубина выдачи — не больше 2000 (per_page=10&page=199 можно, page=200 — ошибка). Параметры, где указано «можно несколько», передаются как key=value&key=value.

Параметр Где Тип Обяз. Описание
text query string нет Поисковая фраза (поддерживается язык запросов)
search_field query string нет Область поиска из vacancy_search_fields в /dictionaries; можно несколько
area query string нет Регион из /areas; можно несколько
metro query string нет Ветка или станция метро из /metro; можно несколько
professional_role query string нет Профессиональная роль из /professional_roles
industry query string нет Индустрия компании из /industries; можно несколько
employer_id query string нет Работодатель; можно несколько
experience query string нет Опыт из experience в /dictionaries; можно несколько
employment_form query string нет Тип занятости из vacancy_search_employment_form; можно несколько
work_format query string нет Формат работы из work_format; можно несколько
work_schedule_by_days query string нет График работы; можно несколько
working_hours query string нет Рабочие часы в день; можно несколько
salary query number нет Размер зарплаты; валюта по умолчанию RUR
currency query string нет Код валюты из currency в /dictionaries (только вместе с salary)
label query string нет Метки вакансий из vacancy_label (например, with_salary); можно несколько
excluded_text query string нет Исключить вакансии с этими словами (через запятую)
education query string нет not_required_or_not_specified, special_secondary, higher
period query number нет Поиск за последние N дней
date_from query string нет Нижняя граница даты публикации (ISO 8601); нельзя вместе с period
date_to query string нет Верхняя граница даты публикации; нельзя вместе с period
top_lat query number нет Верхняя граница широты (передавать все четыре гео-параметра)
bottom_lat query number нет Нижняя граница широты
left_lng query number нет Левая граница долготы
right_lng query number нет Правая граница долготы
order_by query string нет Сортировка из vacancy_search_order; для distance нужны sort_point_lat, sort_point_lng
clusters query boolean нет Вернуть кластеры поиска (по умолчанию false)
describe_arguments query boolean нет Вернуть описание применённых параметров (arguments)
no_magic query boolean нет Отключить автоматическое преобразование текстового запроса в параметры
responses_count_enabled query boolean нет Добавить поле counters с числом откликов
page query number нет Номер страницы, по умолчанию 0
per_page query number нет Элементов на странице, по умолчанию 10, максимум 100

GET /vacancies/{vacancy_id} — Просмотр вакансии

Коды: 403 — нужна капча, 404 — вакансия не существует или нет прав, 429 — слишком много запросов.

Параметр Где Тип Обяз. Описание
vacancy_id path string да Идентификатор вакансии
HH-User-Agent header string да Название приложения и почта разработчика

GET /vacancies/{vacancy_id}/similar_vacancies — Похожие вакансии

Параметр Где Тип Обяз. Описание
vacancy_id path string да Идентификатор вакансии

POST /vacancies — Публикация вакансии

При успешной публикации списываются услуги работодателя; конкретный пакет задаётся employer_service_id, иначе выбирается автоматически. Все вакансии проходят ручную модерацию и появляются в поиске через несколько минут. Успех — 201.

Параметр Где Тип Обяз. Описание
ignore_duplicates query boolean нет Принудительно добавить дубликат
name body string да Название
description body string да Описание в HTML
area body object да Регион
professional_roles body array да Профессиональные роли
vacancy_properties body object нет Свойства публикации (заменяет устаревшие type и billing_type)
employer_service_id body string нет Пакет услуг из suitable_packages[].employer_service_id
salary_range body object нет Зарплата (поле salary устарело)
address body object нет Адрес
experience body object нет Опыт работы
employment_form body object нет Тип занятости
work_format body array нет Форматы работы
work_schedule_by_days body array нет Графики работы
working_hours body array нет Рабочие часы в день
key_skills body array нет Ключевые навыки
contacts body object нет Контакты; при использовании нужен атрибут phones
code body string нет Внутренний код вакансии
department body object нет Департамент работодателя
manager body object нет Менеджер вакансии
previous_id body string нет ID архивной вакансии для связи с новой
response_letter_required body boolean нет Обязательно сопроводительное письмо
test body object нет Тест для вакансии

PUT /vacancies/{vacancy_id} — Редактирование вакансии

Изменяет переданные поля. Составные поля (salary_range, contacts, professional_roles) передаются целиком. billing_type и manager меняются отдельным запросом.

Параметр Где Тип Обяз. Описание
vacancy_id path string да Идентификатор вакансии
ignore_duplicates query boolean нет Игнорировать появление дубликата (по умолчанию false)
ignore_replacement_warning query boolean нет Игнорировать ошибку о значительном изменении (по умолчанию true, есть риск блокировки)
name body string нет Название
description body string нет Описание в HTML
salary_range body object нет Зарплата (целиком)
contacts body object нет Контакты (целиком)
professional_roles body array нет Профессиональные роли (целиком)

GET /employers/{employer_id}/vacancies/active — Опубликованные вакансии работодателя

Параметр Где Тип Обяз. Описание
employer_id path string да Идентификатор работодателя
manager_ids query string нет ID менеджеров через запятую, например manager_ids=1,2,3
all_accessible query boolean нет Вакансии текущего пользователя и менеджеров, к которым есть доступ
text query string нет Поиск по названию
area query string нет Регион вакансии
department_id query string нет Департамент работодателя
resume_id query string нет Только вакансии, подходящие резюме (без других параметров)
order_by query string нет Сортировка из employer_active_vacancies_order
page query number нет Номер страницы, с 0
per_page query number нет Элементов на странице, по умолчанию 20, максимум 50

PUT /employers/{employer_id}/vacancies/archived/{vacancy_id} — Архивация вакансии

Успех — 204.

Параметр Где Тип Обяз. Описание
employer_id path string да Идентификатор работодателя
vacancy_id path string да Идентификатор вакансии

GET /resumes — Поиск резюме

Результаты группируются по соискателю (одно резюме на соискателя). Глубина выдачи — не больше 2000. Для тонкой настройки text передаётся вся триада text.logic, text.field, text.period.

Пример:

Параметр Где Тип Обяз. Описание
text query string нет Поисковая фраза; можно несколько
text.logic query string нет Логика поиска из resume_search_logic
text.field query string нет Где искать, из resume_search_fields (через запятую)
text.period query string нет Период опыта работы
area query string нет Регион; можно несколько
relocation query string нет Готовность к переезду (вместе с area)
age_from query string нет Возраст от
age_to query string нет Возраст до
salary_from query number нет Желаемая зарплата от
salary_to query number нет Желаемая зарплата до
currency query string нет Код валюты
experience query string нет Опыт работы; можно несколько
skill query string нет ID ключевых навыков
professional_role query string нет Профессиональная роль; можно несколько
language query string нет Язык в формате language.level, например ita.c2
label query string нет Доп. фильтр из resume_search_label; можно несколько
period query number нет Резюме, опубликованные за N дней
date_from query string нет Дата начала поиска; нельзя с period
date_to query string нет Дата окончания (только с date_from)
vacancy_id query string нет Поиск резюме, похожих на вакансию
search_in_responses query boolean нет Искать только среди откликнувшихся на вакансии компании
folder query string нет Папки с отобранными резюме, например folder=111&folder=222
order_by query string нет Сортировка из resume_search_order
page query number нет Номер страницы, с 0
per_page query number нет По умолчанию 20, максимум 100

Пример запроса:

GET /resumes?text=программист&text=java

GET /resumes/{resume_id} — Просмотр резюме

Требуется платный доступ. Если полные данные недоступны, часть полей придёт null, can_view_full_info = false, contact_view_status = NONE. Ссылки на просмотр с контактами и скачивание (PDF, RTF) приходят в поле actions; переход по ним списывает контакт.

Параметр Где Тип Обяз. Описание
resume_id path string да Идентификатор резюме
with_negotiations_history query boolean нет Добавить negotiations_history.vacancies (до трёх вакансий)
with_creds query boolean нет Добавить поле creds
with_job_search_status query boolean нет Добавить статус поиска работы

GET /negotiations — Список откликов и приглашений

По умолчанию сортировка по дате обновления, от новых к старым. Активные отклики — ?status=active.

Параметр Где Тип Обяз. Описание
vacancy_id query string да ID вакансии (обязателен для работодателя)
status query string нет Статус из applicant_negotiation_status
order_by query string нет Сортировка из negotiations_order
order query string нет asc или desc
has_updates query boolean нет Только с непросмотренными сообщениями
with_job_search_status query boolean нет Вернуть статус поиска работы кандидата
with_generated_collections query boolean нет Вернуть сгенерированные коллекции
page query number нет Номер страницы
per_page query number нет По умолчанию 20

GET /negotiations/{id} — Просмотр отклика или приглашения

URL берётся из items[].url списка откликов.

Параметр Где Тип Обяз. Описание
id path string да Идентификатор отклика

PUT /negotiations/{collection_name}/{nid} — Действие с откликом

Меняет работодательское (employer_state) или соискательское (state) состояние: отложить, пригласить на интервью, отказать. Доступные действия и их URL — в actions[] списка откликов; аргументы из actions[].arguments передаются как application/x-www-form-urlencoded. Успех — 204.

Параметр Где Тип Обяз. Описание
collection_name path string да Коллекция из collections[].id
nid path string да Идентификатор отклика

GET /common/chats — Список чатов

Параметр Где Тип Обяз. Описание
page query integer нет Страница, 0–50
per_page query integer нет Чатов на странице, 1–20 (по умолчанию 20)
filter_unread query boolean нет Только непрочитанные
filter_has_text_message query boolean нет Только с активной перепиской (для работодателя)
vacancy_status query string нет all (по умолчанию), with, without
filter_with_vacancy_ids query string нет Список ID вакансий, например [1,2,3] (до 100)

GET /common/chats/{chat_id}/messages — Сообщения чата

Параметр Где Тип Обяз. Описание
chat_id path string да Идентификатор чата
start_message_id query string нет С какого сообщения выбирать
limit query integer нет 1–50, по умолчанию 10
order query string нет next (по умолчанию) или prev

POST /common/chats/{chat_id}/messages — Отправка сообщения в чат

Вместе с ключом идемпотентности передаётся либо текст, либо ID загруженных файлов. Успех — 201; 409 — повтор idempotency_key.

Параметр Где Тип Обяз. Описание
chat_id path string да Идентификатор чата
idempotency_key body string да Уникальный ключ сообщения (UUID)
text body string нет Текст сообщения
file_upload_ids body array нет upload_id загруженного файла (1 элемент)

Пример запроса:

{
"idempotency_key": "8abcdef8-4abc-4edf-1234-1234567890ab",
"text": "Cъешь же ещё этих мягких французских булок, да выпей чаю"
}

GET /employers — Поиск работодателей

Глубина выдачи — не больше 5000.

Параметр Где Тип Обяз. Описание
text query string нет Поиск по названию и описанию
area query string нет Регион; можно несколько
type query string нет Тип из employer_type; можно несколько
only_with_vacancies query boolean нет Только с открытыми вакансиями
sort_by query string нет by_name (по умолчанию) или by_vacancies_open
page query number нет Номер страницы, с 0
per_page query number нет По умолчанию 20, максимум 100

GET /employers/{employer_id} — Информация о работодателе

Параметр Где Тип Обяз. Описание
employer_id path string да Идентификатор работодателя

GET /dictionaries — Справочники полей

Значения справочников могут меняться в любой момент.

Параметр Где Тип Обяз. Описание
locale query string нет Локаль, по умолчанию RU

GET /areas — Дерево регионов

Параметр Где Тип Обяз. Описание
additional_case query string нет prepositional — название в предложном падеже (только для русской локали)

GET /professional_roles — Справочник профессиональных ролей

Параметр Где Тип Обяз. Описание
locale query string нет Локаль

POST /webhook/subscriptions — Подписка на уведомления

Успех — 201, в ответе id подписки. Только для работодателя.

Пример колбэка:

Параметр Где Тип Обяз. Описание
actions body array да Список событий
url body string да URL для POST-уведомлений

Пример запроса:

{
"action_type": "string",
"id": "string",
"payload": {
"chat_id": "string",
"employer_id": "string",
"negotiation_date": "string",
"resume_id": "string",
"topic_id": "string",
"vacancy_id": "string"
},
"subscription_id": "string",
"user_id": "string"
}

GET /webhook/subscriptions — Список подписок

Параметр Где Тип Обяз. Описание
HH-User-Agent header string да Название приложения и почта разработчика

DELETE /webhook/subscriptions/{subscription_id} — Удаление подписки

Параметр Где Тип Обяз. Описание
subscription_id path string да Идентификатор подписки

Нюансы

Ошибки

Код Описание
400 Ошибка в параметрах запроса; нет заголовка User-Agent/HH-User-Agent
403 Ошибка авторизации, нет прав или требуется капча
404 Объект не найден или недоступен
409 Конфликт (например, повтор idempotency_key)
429 Слишком много запросов или превышен дневной лимит просмотра резюме
500 Внутренняя ошибка
503 Сбой сервиса

Ограничения

Источники


Если этого недостаточно — официальная документация: https://api.hh.ru/openapi/redoc JSON: https://mcp-everything.ru/api/integrations/hh-api. MCP: https://mcp-everything.ru/mcp