---
slug: "huntflow"
name: "Хантфлоу API v2"
vendor: "Хантфлоу"
industry: "hr"
docsUrl: "https://api.huntflow.ru/v2/docs"
version: 2
updatedAt: "2026-10-24"
---

# Хантфлоу API v2

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

API рекрутинговой CRM Хантфлоу: организации и пользователи, вакансии и заявки на вакансии, кандидаты и их резюме, движение кандидатов по этапам подбора, загрузка и распознавание файлов резюме, метки, справочники, вебхуки, офферы, анкеты и журнал действий. Первая версия API устарела и не поддерживается — используется v2.

## Сценарии

### Добавить кандидата из формы на сайте на вакансию

Отклик с карьерного сайта сразу попадает в Хантфлоу: кандидат, резюме и этап подбора.

1. Создай токен: «Настройки» → «API» → «Добавить токен». access_token живёт 7 дней, refresh_token — 14; при ответе 401 с detail = token_expired обнови пару через POST /token/refresh.
2. Узнай ID организации: GET /accounts — account_id нужен во всех остальных методах.
3. Загрузи файл резюме: POST /accounts/{account_id}/upload (multipart) с заголовком x-file-parse: true — Хантфлоу распознает ФИО, контакты и опыт. Сохрани id файла.
4. Создай кандидата: POST /accounts/{account_id}/applicants с first_name, last_name, phone, email и externals — резюме с файлом.
5. Добавь кандидата на вакансию: POST /accounts/{account_id}/applicants/{applicant_id}/vacancy с vacancy и status — ID этапа подбора (список этапов — /accounts/{account_id}/vacancies/statuses).

```bash
H="Authorization: Bearer $HF_TOKEN"
API=https://api.huntflow.ru/v2/accounts/<account_id>

FILE_ID=$(curl -s -X POST "$API/upload" -H "$H" -H 'x-file-parse: true' -F file=@cv.pdf | jq -r .id)

APPLICANT=$(curl -s -X POST "$API/applicants" -H "$H" -H 'Content-Type: application/json' \
  -d "{\"first_name\": \"Иван\", \"last_name\": \"Петров\", \"phone\": \"+79990001122\", \"email\": \"ivan@example.ru\",
       \"externals\": [{\"auth_type\": \"NATIVE\", \"data\": {\"body\": \"Отклик с сайта\"}, \"files\": [$FILE_ID]}]}" | jq -r .id)

curl -X POST "$API/applicants/$APPLICANT/vacancy" -H "$H" -H 'Content-Type: application/json' \
  -d '{"vacancy": 101, "status": 1001, "comment": "Отклик с карьерного сайта"}'
```

### Открыть вакансию из своей системы

Заявка на подбор согласована во внутренней системе — вакансия появляется в Хантфлоу.

1. Создай вакансию: POST /accounts/{account_id}/vacancies с position, company, money, body, requirements, conditions (HTML) и fill_quotas — квотой найма с deadline и applicants_to_hire.
2. Добавь коллег-рекрутеров через coworkers, скрыть вакансию от остальных — hidden = true.
3. Проверь список: GET /accounts/{account_id}/vacancies с state = OPEN и mine = true — только вакансии текущего пользователя.

```bash
curl -X POST https://api.huntflow.ru/v2/accounts/<account_id>/vacancies \
  -H "Authorization: Bearer $HF_TOKEN" -H 'Content-Type: application/json' \
  -d '{
        "position": "Python-разработчик",
        "company": "Отдел разработки",
        "money": "200 000 – 300 000 ₽",
        "requirements": "<ul><li>Python 3, FastAPI</li></ul>",
        "fill_quotas": [{"deadline": "2026-12-01", "applicants_to_hire": 2}]
      }'
```

### Выгрузить кандидатов по вакансии и этапам

Воронка подбора для отчёта: кто на каком этапе по каждой вакансии.

1. Для массовой выгрузки используй курсорный поиск: GET /accounts/{account_id}/applicants/search_by_cursor с vacancy, status (ID этапов) и only_current_status = true — только те, кто сейчас на этапе.
2. Для следующей страницы передай next_page_cursor из ответа — остальные параметры тогда не учитываются.
3. Для простых выборок подходит GET /accounts/{account_id}/applicants с vacancy_id и status, постранично через page и count.

```bash
curl -G https://api.huntflow.ru/v2/accounts/<account_id>/applicants/search_by_cursor \
  -H "Authorization: Bearer $HF_TOKEN" \
  -d vacancy=101 -d status=1002 -d only_current_status=true -d count=100
```

### Получать события через вебхук

Реагировать на смену этапа кандидата или новую вакансию сразу: уведомить менеджера, завести сотрудника в HR-системе.

1. Создай вебхук: POST /accounts/{account_id}/hooks с url, secret, active = true и webhook_events — нужными событиями (APPLICANT, VACANCY, RESPONSE, OFFER и др.).
2. Хантфлоу присылает события POST-запросом на url. Используй secret, чтобы отличать настоящие запросы, — способ проверки описан в документации вебхуков.
3. По ID из события получай актуальные данные: например, GET /accounts/{account_id}/applicants с vacancy_id.

```bash
curl -X POST https://api.huntflow.ru/v2/accounts/<account_id>/hooks \
  -H "Authorization: Bearer $HF_TOKEN" -H 'Content-Type: application/json' \
  -d '{"url": "https://example.ru/huntflow/webhook", "secret": "s3cr3t_Random_42", "active": true, "webhook_events": ["APPLICANT", "VACANCY"]}'
```

## Базовые URL

- Боевой: `https://api.huntflow.ru/v2`
- Тестовый (песочница): `https://sandbox.huntflow.dev`
- Официальный Python-клиент Хантфлоу по умолчанию указывает хост .: `https://api.huntflow.ai`

## Авторизация

Тип: Bearer-токен

Токен создаётся в настройках Хантфлоу: «Настройки» → «API» → «Добавить токен»; выдаётся пара `access_token` и `refresh_token`. Все запросы передают заголовок `Authorization: Bearer <access_token>`.

- `access_token` действует 7 дней, `refresh_token` — 14 дней; если refresh-токен не использовать 14 дней, пару нужно создать заново.
- Истёкший токен даёт `401` с `type: authorization_error` и `detail: token_expired` — тогда вызывайте `POST /token/refresh`.

## Методы

### POST /token/refresh — Обновление токенов

В ответе: `access_token`, `refresh_token`, `expires_in`.

| Параметр | Где | Тип | Обяз. | Описание |
|---|---|---|---|---|
| `refresh_token` | body | string | да | Refresh-токен |

### GET /me — Текущий пользователь

Информация о владельце токена.

### GET /accounts — Доступные организации

Список организаций, к которым есть доступ; `account_id` из ответа нужен в остальных методах.

### GET /accounts/{account_id}/vacancies — Список вакансий

| Параметр | Где | Тип | Обяз. | Описание |
|---|---|---|---|---|
| `account_id` | path | integer | да | ID организации |
| `count` | query | integer | нет | Элементов на странице, по умолчанию 30 |
| `page` | query | integer | нет | Номер страницы, по умолчанию 1 |
| `mine` | query | boolean | нет | Только вакансии, с которыми работает текущий пользователь |
| `state` | query | string | нет | Состояние вакансии (можно несколько) |

### POST /accounts/{account_id}/vacancies — Создание вакансии

Также: `GET`/`PUT`/`PATCH`/`DELETE /accounts/{account_id}/vacancies/{vacancy_id}`; этапы подбора — `GET /accounts/{account_id}/vacancies/statuses`.

| Параметр | Где | Тип | Обяз. | Описание |
|---|---|---|---|---|
| `account_id` | path | integer | да | ID организации |
| `position` | body | string | да | Название вакансии |
| `company` | body | string | нет | Отдел или компания |
| `account_division` | body | integer | нет | ID подразделения |
| `account_region` | body | integer | нет | ID региона |
| `money` | body | string | нет | Зарплата |
| `priority` | body | integer | нет | Приоритет |
| `hidden` | body | boolean | нет | Скрыть от коллег, по умолчанию false |
| `state` | body | string | нет | Состояние, по умолчанию OPEN |
| `coworkers` | body | array | нет | ID коллег, работающих с вакансией |
| `body` | body | string | нет | Обязанности (HTML) |
| `requirements` | body | string | нет | Требования (HTML) |
| `conditions` | body | string | нет | Условия (HTML) |
| `files` | body | array | нет | ID прикреплённых файлов |
| `fill_quotas` | body | array | да | Квота найма: deadline, applicants_to_hire (один элемент) |

### GET /accounts/{account_id}/applicants — Список кандидатов

| Параметр | Где | Тип | Обяз. | Описание |
|---|---|---|---|---|
| `account_id` | path | integer | да | ID организации |
| `count` | query | integer | нет | Элементов на странице, по умолчанию 30 |
| `page` | query | integer | нет | Номер страницы, по умолчанию 1 |
| `status` | query | integer | нет | ID этапа подбора |
| `vacancy_id` | query | integer | нет | ID вакансии |
| `agreement_state` | query | string | нет | Статус согласия на обработку ПДн; нельзя вместе со status |

### GET /accounts/{account_id}/applicants/search_by_cursor — Поиск кандидатов

Если передан `next_page_cursor`, остальные параметры не учитываются.

| Параметр | Где | Тип | Обяз. | Описание |
|---|---|---|---|---|
| `account_id` | path | integer | да | ID организации |
| `next_page_cursor` | query | string | нет | Курсор следующей страницы |
| `q` | query | string | нет | Поисковый запрос |
| `status` | query | array | нет | ID этапов подбора |
| `vacancy` | query | array | нет | ID вакансий; null — кандидаты без вакансии |
| `only_current_status` | query | boolean | нет | Только кандидаты, находящиеся сейчас на этапе |
| `account_source` | query | array | нет | ID источников резюме |
| `count` | query | integer | нет | Элементов на странице, по умолчанию 30 |

### POST /accounts/{account_id}/applicants — Создание кандидата

Также: `GET`/`PATCH`/`DELETE /accounts/{account_id}/applicants/{applicant_id}`.

| Параметр | Где | Тип | Обяз. | Описание |
|---|---|---|---|---|
| `account_id` | path | integer | да | ID организации |
| `first_name` | body | string | нет | Имя |
| `last_name` | body | string | нет | Фамилия |
| `middle_name` | body | string | нет | Отчество |
| `phone` | body | string | нет | Телефон |
| `email` | body | string | нет | Email |
| `position` | body | string | нет | Желаемая должность |
| `company` | body | string | нет | Компания |
| `money` | body | string | нет | Зарплатные ожидания |
| `birthday` | body | string | нет | Дата рождения |
| `photo` | body | integer | нет | ID фото |
| `externals` | body | array | нет | Резюме (одно): auth_type, account_source, data.body, files |
| `social` | body | array | нет | Соцсеть (одна): social_type (TELEGRAM), value |

### POST /accounts/{account_id}/applicants/{applicant_id}/vacancy — Добавление кандидата на вакансию

Смена этапа по уже добавленной вакансии — `PUT` по тому же пути.

| Параметр | Где | Тип | Обяз. | Описание |
|---|---|---|---|---|
| `account_id` | path | integer | да | ID организации |
| `applicant_id` | path | integer | да | ID кандидата |
| `vacancy` | body | integer | да | ID вакансии |
| `status` | body | integer | да | ID этапа подбора |
| `comment` | body | string | нет | Комментарий |
| `rejection_reason` | body | integer | нет | ID причины отказа (для этапа отказа) |
| `fill_quota` | body | integer | нет | ID квоты (для этапа «вышел на работу») |
| `employment_date` | body | string | нет | Дата выхода (для этапа «вышел на работу») |
| `files` | body | array | нет | ID файлов, до 15 |
| `calendar_event` | body | object | нет | Событие календаря (интервью) |
| `email` | body | object | нет | Письмо кандидату |

### POST /accounts/{account_id}/upload — Загрузка и распознавание файла

Файл отправляется в `multipart/form-data`.

| Параметр | Где | Тип | Обяз. | Описание |
|---|---|---|---|---|
| `account_id` | path | integer | да | ID организации |
| `file` | body | file | да | Файл |
| `x-file-parse` | header | boolean | нет | Распознать поля резюме |
| `x-ignore-lastname` | header | string | нет | Фамилии, которые игнорировать при распознавании |
| `x-ignore-email` | header | string | нет | Email, которые игнорировать |

### POST /accounts/{account_id}/hooks — Создание вебхука

| Параметр | Где | Тип | Обяз. | Описание |
|---|---|---|---|---|
| `account_id` | path | integer | да | ID организации |
| `url` | body | string | да | URL вебхука |
| `secret` | body | string | да | Секретный ключ |
| `active` | body | boolean | да | Активен ли вебхук |
| `webhook_events` | body | array | да | APPLICANT, VACANCY, RESPONSE, OFFER, VACANCY-REQUEST, RECRUITMENT-EVALUATION, SURVEY-QUESTIONARY |
| `type` | body | string | нет | USER (по умолчанию) или APPLICATION |

## Нюансы

- Почти все методы работают в контексте организации: `account_id` берётся из `GET /accounts`.
- ID этапов подбора — из `GET /accounts/{account_id}/vacancies/statuses`, причины отказа — из `/rejection_reasons`, источники резюме — из `/applicants/sources`.
- Для массовой выборки кандидатов удобнее курсорный поиск `search_by_cursor`.
- Есть также методы заявок на вакансии, мультивакансий, меток, справочников, регионов, подразделений, офферов, анкет, журнала действий (`action_logs`) и производственного календаря.

## Ошибки

| Код | Описание |
|---|---|
| `401` | Нет авторизации или токен истёк (type: authorization_error, detail: token_expired) |

## Источники

- [Huntflow API Reference v2](https://api.huntflow.ru/v2/docs)
- [Спецификация OpenAPI](https://api.huntflow.ru/v2/openapi.json)
- [Официальный Python-клиент Хантфлоу](https://github.com/huntflow/huntflow-api-client-python)
- [Хантфлоу API v1 (устарел)](https://github.com/huntflow/api)

---

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