Отрасль: 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 для своего сайта, бота или аналитики зарплат.
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.
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.
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
Отправлять кандидатам сообщения из своей системы и читать ответы.
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.\"}"
Узнавать о новых откликах и сообщениях сразу, без опроса.
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": "<тип события>"}]}'
https://api.hh.ru?host=Тип: OAuth 2.0
OAuth 2.0. Токен передаётся в заголовке Authorization: Bearer {ACCESS_TOKEN}.
https://hh.ru/oauth/authorize?response_type=code&client_id={client_id}&state={state}&redirect_uri={redirect_uri}, затем authorization_code из редиректа обменивается на access_token и refresh_token запросом POST https://api.hh.ru/token. Поддерживается PKCE (code_challenge, code_challenge_method=S256).POST https://api.hh.ru/token с refresh_token; refresh-токен одноразовый и работает только после истечения access_token (срок — expires_in, в секундах).https://dev.hh.ru/admin.Параметры /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)
Тело — 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 |
Работает только для действующего токена пользователя; токен приложения так инвалидировать нельзя. После инвалидации нужно авторизоваться заново. Успех — 204.
| Параметр | Где | Тип | Обяз. | Описание |
|---|---|---|---|---|
HH-User-Agent |
header | string | да | Название приложения и почта разработчика |
В ответе: auth_type, id, email, first_name, last_name, is_applicant, is_employer, employer, manager, counters и др.
| Параметр | Где | Тип | Обяз. | Описание |
|---|---|---|---|---|
HH-User-Agent |
header | string | да | Название приложения и почта разработчика |
Неизвестные параметры игнорируются. Без токена после первого запроса может потребоваться капча. Глубина выдачи — не больше 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 |
Коды: 403 — нужна капча, 404 — вакансия не существует или нет прав, 429 — слишком много запросов.
| Параметр | Где | Тип | Обяз. | Описание |
|---|---|---|---|---|
vacancy_id |
path | string | да | Идентификатор вакансии |
HH-User-Agent |
header | string | да | Название приложения и почта разработчика |
| Параметр | Где | Тип | Обяз. | Описание |
|---|---|---|---|---|
vacancy_id |
path | string | да | Идентификатор вакансии |
При успешной публикации списываются услуги работодателя; конкретный пакет задаётся 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 | нет | Тест для вакансии |
Изменяет переданные поля. Составные поля (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 | нет | Профессиональные роли (целиком) |
| Параметр | Где | Тип | Обяз. | Описание |
|---|---|---|---|---|
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 |
Успех — 204.
| Параметр | Где | Тип | Обяз. | Описание |
|---|---|---|---|---|
employer_id |
path | string | да | Идентификатор работодателя |
vacancy_id |
path | string | да | Идентификатор вакансии |
Результаты группируются по соискателю (одно резюме на соискателя). Глубина выдачи — не больше 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
Требуется платный доступ. Если полные данные недоступны, часть полей придёт 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 | нет | Добавить статус поиска работы |
По умолчанию сортировка по дате обновления, от новых к старым. Активные отклики — ?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 |
URL берётся из items[].url списка откликов.
| Параметр | Где | Тип | Обяз. | Описание |
|---|---|---|---|---|
id |
path | string | да | Идентификатор отклика |
Меняет работодательское (employer_state) или соискательское (state) состояние: отложить, пригласить на интервью, отказать. Доступные действия и их URL — в actions[] списка откликов; аргументы из actions[].arguments передаются как application/x-www-form-urlencoded. Успех — 204.
| Параметр | Где | Тип | Обяз. | Описание |
|---|---|---|---|---|
collection_name |
path | string | да | Коллекция из collections[].id |
nid |
path | string | да | Идентификатор отклика |
| Параметр | Где | Тип | Обяз. | Описание |
|---|---|---|---|---|
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) |
| Параметр | Где | Тип | Обяз. | Описание |
|---|---|---|---|---|
chat_id |
path | string | да | Идентификатор чата |
start_message_id |
query | string | нет | С какого сообщения выбирать |
limit |
query | integer | нет | 1–50, по умолчанию 10 |
order |
query | string | нет | next (по умолчанию) или prev |
Вместе с ключом идемпотентности передаётся либо текст, либо 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ъешь же ещё этих мягких французских булок, да выпей чаю"
}
Глубина выдачи — не больше 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 |
| Параметр | Где | Тип | Обяз. | Описание |
|---|---|---|---|---|
employer_id |
path | string | да | Идентификатор работодателя |
Значения справочников могут меняться в любой момент.
| Параметр | Где | Тип | Обяз. | Описание |
|---|---|---|---|---|
locale |
query | string | нет | Локаль, по умолчанию RU |
| Параметр | Где | Тип | Обяз. | Описание |
|---|---|---|---|---|
additional_case |
query | string | нет | prepositional — название в предложном падеже (только для русской локали) |
| Параметр | Где | Тип | Обяз. | Описание |
|---|---|---|---|---|
locale |
query | string | нет | Локаль |
Успех — 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"
}
| Параметр | Где | Тип | Обяз. | Описание |
|---|---|---|---|---|
HH-User-Agent |
header | string | да | Название приложения и почта разработчика |
| Параметр | Где | Тип | Обяз. | Описание |
|---|---|---|---|---|
subscription_id |
path | string | да | Идентификатор подписки |
page=N&per_page=M, нумерация с нуля; ответ — found, per_page, pages, page, items./cors (HEAD, GET, POST, PUT, DELETE), для JSONP — ?callback=callback_name.2xx или 409 для дубликата (определяется по id). Без ответа за 5 секунд колбэк отправляется повторно; доставка не гарантирована. При долгих сбоях подписка блокируется, при отзыве доступа удаляется./negotiations/{nid}/messages устарели — переписка ведётся через /common/chats.hidden_fields.| Код | Описание |
|---|---|
400 |
Ошибка в параметрах запроса; нет заголовка User-Agent/HH-User-Agent |
403 |
Ошибка авторизации, нет прав или требуется капча |
404 |
Объект не найден или недоступен |
409 |
Конфликт (например, повтор idempotency_key) |
429 |
Слишком много запросов или превышен дневной лимит просмотра резюме |
500 |
Внутренняя ошибка |
503 |
Сбой сервиса |
per_page не больше 100 для поиска.GET /employers/{employer_id}/managers/{manager_id}/limits/resume.Если этого недостаточно — официальная документация: https://api.hh.ru/openapi/redoc JSON: https://mcp-everything.ru/api/integrations/hh-api. MCP: https://mcp-everything.ru/mcp