Jobok API
Данные рынка из сборов навыков hh.ru. Ключ — в разделе «API» кабинета
- Создайте ключ в разделе «API» кабинета — он показывается один раз.
- Передавайте его в каждом запросе. Начните с метода «Ключ и пределы» — он покажет пределы ключа.
- ИИ-ассистенту подключите MCP или отдайте эту документацию: кнопка «Скопировать Markdown» вверху, файл — /v1/docs.md.
Спека OpenAPI для генераторов клиентов — /v1/openapi.json
Авторизация
Ключ передаётся в каждом запросе заголовком:
Authorization: Bearer jbk_…
Адрес API — https://api.jobok.ru. Ключ открывает только ручки /v1: войти с ним в кабинет нельзя. Вызывать API — с сервера, из скрипта или бота: из браузера на чужом сайте не выйдет, CORS открыт только сайту Jobok, а ключ в браузере увидел бы любой посетитель.
Пределы
Не больше 60 запросов в минуту и 1000 в сутки — на все ключи владельца вместе. Сутки — по Москве. У ключа может быть свой суточный предел, меньше общего. Сверка с вакансией, которую ещё не читали, берёт её с hh.ru — таких не больше 50 в сутки; прочитанные отвечают из кэша без этого предела. Каждый ответ несёт заголовки:
X-RateLimit-Limit-Requests | суточный предел этого ключа |
X-RateLimit-Remaining-Requests | сколько запросов осталось на сегодня |
X-RateLimit-Reset-Requests | секунд до полуночи по Москве |
Retry-After | на отказе 429 — через сколько секунд повторить |
Ошибки
Отказ всегда в одной форме. Ветвиться — по type: текст в message для человека и может меняться.
{ "error": { "type": "not_found", "message": "…" } }| type | Статус | Когда |
|---|---|---|
invalid_api_key | 401 | Ключа нет в заголовке, он не распознан или удалён |
key_expired | 401 | Срок ключа истёк |
rate_limit_exceeded | 429 | Исчерпан предел — повторить через Retry-After секунд |
not_found | 404 | Сбора нет, у него ещё нет результата или такого метода нет вовсе |
invalid_request | 400 | Неверные параметры или тело запроса — не JSON |
request_too_large | 413 | Тело запроса больше 100 КБ |
hh_unavailable | 502 | hh.ru не отдал страницу вакансии — повторить позже |
server_error | 500 | Сбой на нашей стороне |
Ключ
Пределы ключа и сколько из них потрачено сегодня
Ключ и пределы
GET/v1/key
Пределы ключа и сколько потрачено за сегодняшние сутки по Москве. Этот запрос тоже идёт в счёт
Ответ 200
namestringhintstringcreatedAtstringexpiresAtstring | nullnull — бессрочный
limitsobjectВложенные поля: 4
perMinutenumberЗапросов в минуту на все ключи владельца
perDaynumberЗапросов в сутки по Москве на все ключи владельца
keyPerDaynumber | nullСвой суточный предел этого ключа; null — только общий
vacancyFetchesPerDaynumberВакансий в сутки, которые сверка может прочитать с hh.ru, на все ключи владельца; вакансии из кэша в счёт не идут
usedTodayobjectСчёт сегодняшних суток по Москве, включая этот запрос
Вложенные поля: 3
totalnumberЗапросов за сегодня по всем ключам владельца
keynumberИз них — этим ключом
vacancyFetchesnumberВакансий прочитано с hh.ru по всем ключам владельца
Отказы
401 | Ключа нет, он удалён или истёк |
429 | Исчерпан предел — см. Retry-After |
curl -H "Authorization: Bearer $JOBOK_KEY" \ "https://api.jobok.ru/v1/key"
Ответ 200
{
"name": "Бот в Telegram",
"hint": "jbk_AbCd…Wx12",
"createdAt": "2026-10-11T19:03:06.623Z",
"expiresAt": null,
"limits": {
"perMinute": 60,
"perDay": 1000,
"keyPerDay": null,
"vacancyFetchesPerDay": 50
},
"usedToday": {
"total": 94,
"key": 1,
"vacancyFetches": 7
}
}Сборы навыков
Готовые сборы навыков с hh.ru: что требуют работодатели по профессии и сколько платят
Список сборов
GET/v1/scans
Готовые сборы навыков, свежие сверху, не больше 50
Ответ 200 — массив объектов
idstringqueriesstring[]Формулировки названия вакансии, по которым шёл сбор
status"running" | "done" | "stopped" | "failed"done — досчитан; stopped — остановлен вручную, посчитано то, что успели; running — идёт пересчёт, данные прошлого прогона
scannednumberСколько вакансий обойдено — база всех долей
finishedAtstring | nullskillCountnumberСколько групп навыков в сборе
salaryobject | nullnull — зарплату не считали или её никто не указал
Вложенные поля: 2
fromnumber | nullМедиана названных нижних границ, ₽ в месяц на руки
tonumber | nullМедиана названных верхних границ, ₽ в месяц на руки
Отказы
401 | Ключа нет, он удалён или истёк |
429 | Исчерпан предел — см. Retry-After |
curl -H "Authorization: Bearer $JOBOK_KEY" \ "https://api.jobok.ru/v1/scans"
Ответ 200
[
{
"id": "cmv1zfxir00041kx2cvn26e1g",
"queries": [
"devops инженер"
],
"status": "done",
"scanned": 407,
"finishedAt": "2026-10-10T05:59:29.578Z",
"skillCount": 112,
"salary": {
"from": 130500,
"to": 226200
}
}
]Сбор целиком
GET/v1/scans/{id}
Навыки с долями и зарплатой, квартили зарплат, слова названий, регионы
Параметры
idstringв путиобязательноid сбора из GET /v1/scans
Ответ 200
idstringqueriesstring[]status"running" | "done" | "stopped" | "failed"done — досчитан; stopped — остановлен вручную, посчитано то, что успели; running — идёт пересчёт, данные прошлого прогона
foundnumberСколько вакансий нашёл hh.ru
scannednumberСколько обойдено — база всех долей
limitHitbooleanhh.ru отдаёт не больше 2000 вакансий на запрос — обойдена не вся выдача
finishedAtstring | nullsalaryobject | nullnull — зарплату не считали
Вложенные поля: 4
fromobjectНижние границы вилок («от»), ₽ в месяц на руки
Вложенные поля: 4
p25number | nullp50number | nullp75number | nullcountnumberПо скольким вакансиям названа эта граница
toobjectВерхние границы вилок («до»), ₽ в месяц на руки
Вложенные поля: 4
p25number | nullp50number | nullp75number | nullcountnumberПо скольким вакансиям названа эта граница
withSalarynumberУ скольких вакансий зарплата пригодна к счёту
ratesAtstring | nullДата курса ЦБ, по которому пересчитана валюта
skillsobject[]Все группы навыков, от частых к редким
Вложенные поля: 6
namestringmembersstring[]Все написания навыка, от частого к редкому
countnumberВо скольких вакансиях встретился
sharenumberДоля от обойдённых вакансий, 0..1
salaryFromnumber | nullМедиана «от» по вакансиям с этим навыком, ₽ в месяц
salaryTonumber | nullМедиана «до» по вакансиям с этим навыком, ₽ в месяц
titleWordsobject[]Вложенные поля: 3
wordstringСлово или устойчивое сочетание из названий вакансий
countnumberemployersnumberУ скольких разных работодателей встретилось
areasobject[]Регионы вакансий
Вложенные поля: 2
namestringcountnumber
Отказы
401 | Ключа нет, он удалён или истёк |
404 | Сбора нет или у него ещё нет результата |
429 | Исчерпан предел — см. Retry-After |
curl -H "Authorization: Bearer $JOBOK_KEY" \ "https://api.jobok.ru/v1/scans/cmv1zfxir00041kx2cvn26e1g"
Ответ 200
{
"id": "cmv1zfxir00041kx2cvn26e1g",
"queries": [
"devops инженер"
],
"status": "done",
"found": 448,
"scanned": 407,
"limitHit": false,
"finishedAt": "2026-10-10T05:59:29.578Z",
"salary": {
"from": {
"p25": 80000,
"p50": 130500,
"p75": 200000,
"count": 68
},
"to": {
"p25": 123467,
"p50": 226200,
"p75": 280000,
"count": 58
},
"withSalary": 91,
"ratesAt": "2026-10-10T00:00:00.000Z"
},
"skills": [
{
"name": "CI/CD",
"members": [
"CI/CD"
],
"count": 47,
"share": 0.1155,
"salaryFrom": 115250,
"salaryTo": 130250
}
],
"titleWords": [
{
"word": "devops-инженер",
"count": 262,
"employers": 204
}
],
"areas": [
{
"name": "Москва",
"count": 213
}
]
}Навыки профессии
GET/v1/skills
Самые частые навыки по профессии — из подходящего готового сбора или из названного по scanId
Параметры
professionstringв запросеНазвание профессии: сбор подбирается по словам названия — все слова одного должны быть в другом
scanIdstringв запросеВзять этот сбор (id из GET /v1/scans), а не подбирать по профессии
Ответ 200
scanobjectСбор, из которого взяты навыки
Вложенные поля: 4
idstringqueriesstring[]scannednumberСколько вакансий обойдено — база долей
finishedAtstring | null
skillsobject[]Самые частые навыки, не больше 40
Вложенные поля: 3
namestringmembersstring[]Все написания — по ним навык ищут в тексте резюме
sharenumberДоля от обойдённых вакансий, 0..1
Отказы
400 | Нет ни profession, ни scanId |
401 | Ключа нет, он удалён или истёк |
404 | Подходящего сбора нет |
429 | Исчерпан предел — см. Retry-After |
curl -H "Authorization: Bearer $JOBOK_KEY" \ "https://api.jobok.ru/v1/skills?profession=devops"
Ответ 200
{
"scan": {
"id": "cmv1zfxir00041kx2cvn26e1g",
"queries": [
"devops инженер"
],
"scanned": 407,
"finishedAt": "2026-10-10T05:59:29.578Z"
},
"skills": [
{
"name": "CI/CD",
"members": [
"CI/CD"
],
"share": 0.1155
}
]
}Сверка резюме
Какие навыки названы в тексте резюме, а каких не хватает — по рынку профессии или по одной вакансии
Сверка с рынком
POST/v1/resume/coverage
Какие частые навыки профессии названы в тексте резюме, а каких не хватает
Тело запроса, JSON
professionstringНазвание профессии: сбор подбирается по словам названия — все слова одного должны быть в другом
scanIdstringВзять этот сбор (id из GET /v1/scans), а не подбирать по профессии
textstringобязательноТекст резюме одной строкой: опыт, «О себе», навыки. Сервер его не хранит и не пишет в журнал
Ответ 200
scanobjectСбор, с навыками которого сверялся текст
Вложенные поля: 4
idstringqueriesstring[]scannednumberСколько вакансий обойдено — база долей
finishedAtstring | null
coveredobject[]Названы в тексте — любым написанием и отдельным словом: «Java» внутри «JavaScript» не считается
Вложенные поля: 3
namestringmembersstring[]Все написания — по ним навык ищут в тексте резюме
sharenumberДоля от обойдённых вакансий, 0..1
missingobject[]Не названы, частые сверху
Вложенные поля: 3
namestringmembersstring[]Все написания — по ним навык ищут в тексте резюме
sharenumberДоля от обойдённых вакансий, 0..1
Отказы
400 | Нет текста или нет ни profession, ни scanId |
401 | Ключа нет, он удалён или истёк |
404 | Подходящего сбора нет |
429 | Исчерпан предел — см. Retry-After |
curl -H "Authorization: Bearer $JOBOK_KEY" \
-H "Content-Type: application/json" \
-d '{"profession":"devops","text":"Настраивал CI/CD в GitLab, инфраструктура на Terraform и Ansible"}' \
"https://api.jobok.ru/v1/resume/coverage"Ответ 200
{
"scan": {
"id": "cmv1zfxir00041kx2cvn26e1g",
"queries": [
"devops инженер"
],
"scanned": 407,
"finishedAt": "2026-10-10T05:59:29.578Z"
},
"covered": [
{
"name": "CI/CD",
"members": [
"CI/CD"
],
"share": 0.1155
}
],
"missing": [
{
"name": "Linux",
"members": [
"Linux"
],
"share": 0.1081
}
]
}Сверка с вакансией
POST/v1/vacancies/{id}/coverage
Какие навыки вакансии hh.ru названы в тексте резюме, а каких не хватает. Вакансия, которую ещё не читали, берётся с hh.ru — у этого свой суточный предел (limits.vacancyFetchesPerDay в GET /v1/key); прочитанная отвечает из кэша без него
Параметры
idstringв путиобязательноНомер вакансии hh.ru — цифры из ссылки hh.ru/vacancy/…
Тело запроса, JSON
textstringобязательноТекст резюме одной строкой: опыт, «О себе», навыки. Сервер его не хранит и не пишет в журнал
Ответ 200
vacancyobjectВложенные поля: 2
idstringurlstring
coveredobject[]Навыки вакансии, названные в тексте резюме
Вложенные поля: 3
namestringmembersstring[]Написания навыка — по ним он ищется в тексте резюме: найденные в вакансии и известные по прошлым сборам
source"key_skills" | "description"key_skills — в блоке «Ключевые навыки» вакансии; description — найден в описании по словарю прошлых сборов
missingobject[]Не названы — сначала из блока «Ключевые навыки», потом из описания
Вложенные поля: 3
namestringmembersstring[]Написания навыка — по ним он ищется в тексте резюме: найденные в вакансии и известные по прошлым сборам
source"key_skills" | "description"key_skills — в блоке «Ключевые навыки» вакансии; description — найден в описании по словарю прошлых сборов
Отказы
400 | Нет текста или id — не номер вакансии |
401 | Ключа нет, он удалён или истёк |
404 | Такой вакансии на hh.ru нет |
429 | Исчерпан предел — см. Retry-After |
502 | hh.ru не отдал страницу вакансии |
curl -H "Authorization: Bearer $JOBOK_KEY" \
-H "Content-Type: application/json" \
-d '{"text":"Настраивал CI/CD в GitLab, инфраструктура на Terraform и Ansible"}' \
"https://api.jobok.ru/v1/vacancies/123456789/coverage"Ответ 200
{
"vacancy": {
"id": "123456789",
"url": "https://hh.ru/vacancy/123456789"
},
"covered": [
{
"name": "Vue.js",
"members": [
"Vue.js",
"Vue",
"VueJS"
],
"source": "key_skills"
}
],
"missing": [
{
"name": "JavaScript",
"members": [
"JavaScript"
],
"source": "key_skills"
}
]
}MCP — для ИИ-ассистентов
Те же методы — инструментами MCP: ассистент сам решает, когда спросить навыки профессии или сверить резюме. Сервер без сессий, по Streamable HTTP; ключ тот же, в заголовке Authorization.
https://api.jobok.ru/v1/mcp
Claude Code
claude mcp add --transport http jobok https://api.jobok.ru/v1/mcp \ --header "Authorization: Bearer $JOBOK_KEY"
Cursor и другие клиенты с файлом mcpServers
{
"mcpServers": {
"jobok": {
"url": "https://api.jobok.ru/v1/mcp",
"headers": {
"Authorization": "Bearer jbk_…"
}
}
}
}Yandex AI Studio: в MCP Hub — внешний MCP-сервер, адрес выше, ключ — как Bearer-токен.
| Инструмент | Что делает |
|---|---|
list_scans | Готовые сборы навыков с hh.ru, свежие сверху: формулировки поиска (профессия), сколько вакансий обойдено, медианы зарплат. id сбора — для get_scan и scanId |
get_scan | Сбор целиком: все навыки с долей вакансий и зарплатой, квартили зарплат, частые слова названий, регионы. Ответ большой — для частых навыков профессии хватит get_skills |
get_skills | Самые частые навыки по профессии (до 40) с долей вакансий, где их просят. Сбор подбирается по названию профессии; если не подходит — scanId из list_scans |
check_resume_coverage | Какие из частых навыков профессии названы в тексте резюме, а каких не хватает. Текст резюме не хранится |
check_vacancy_coverage | Какие навыки конкретной вакансии hh.ru названы в тексте резюме, а каких не хватает. Вакансия — ссылка или номер; непрочитанная берётся с hh.ru, у этого свой суточный предел (get_limits) |
get_limits | Пределы ключа и сколько потрачено сегодня |
Промпты — готовые заготовки разговора: в Claude Code они видны командами, например /mcp__jobok__resume_review.
| Промпт | Что делает |
|---|---|
resume_review | Разбор резюме: каких навыков рынка или вакансии не хватает, что вписать и что убрать |
Каждое сообщение MCP идёт в счёт пределов: подключение — два запроса, список инструментов и каждый вызов — по одному.