Plank help · updated 2026-09-10

Работа с egov.kz (портал электронного правительства)

Как egov.kz устроен изнутри: один JSON API, вход по ЭЦП, где подписываемый документ — константа, двадцать восемь услуг, заказываемых одинаковой тройкой вызовов, — и единственный шаг, где человек нужен всегда.

Agents: fetch the raw markdown of this page at /ru/help/egov-portal.md

Работа с egov.kz (портал электронного правительства)

egov.kz переписан на Next.js поверх одного JSON API. Это меняет постановку задачи: браузерный клиент портала не делает ничего, чего нельзя сделать из скрипта, поэтому гонять egov.kz через браузер незачем — см. §8.

Всё ниже прочитано из клиентского бандла самого портала и проверено на живой системе 10.09.2026 с сервера за пределами Казахстана. Программы для разработчиков и документации нет, поэтому всё это может измениться без предупреждения: пишите код, который падает громко, а не молча возвращает пустоту.


1. Коротко

  • NCALayer не нужен, и это доказано на самом egov. 10.09.2026 логин-документ, подписанный Kalkan на OpenJDK 17 настоящим универсальным ГОСТ-ключом и без всякого NCALayer, был принят: 200 и session_id. См. Подпись ключом ЭЦП РК.
  • Стена не в подписи, а во втором факторе. Приняв подпись, egov шлёт SMS (юрлицу) или push в eGov Mobile (физлицу), и без кода дальше ничего не идёт. Закладывайте человека на вход и никогда — на каждое действие.
  • Один файл ключа закрывает оба шага. Портал спрашивает два разных назначения EKU, но с апреля 2024 НУЦ РК выдаёт одно универсальное ГОСТ-свидетельство, которое обязано нести оба, — kz-ecp-signing §3. Два файла отдаёт только клиент с уцелевшей парой до 2024 года.
  • Двадцать восемь услуг заказываются одинаково, так что одна интеграция покрывает все.

2. API

База: https://fgw.egov.kz, маршрут дописывается как есть. Авторизованные вызовы несут Authorization: Bearer <access_token>; отправляйте Origin: https://egov.kz.

Замерено 10.09.2026: доступен из-за пределов Казахстана, без геоблокировки, без капчи, без CSRF-токена, ошибки приходят типизированными кодами с сообщениями на kk/ru/en:

{"code":"AUTH_ERROR_BAD_SIGNATURE","type":"ERROR",
 "message":{"ru":"ЭЦП недействительна. …","en":"The digital signature is invalid. …"}}

Типизированный код лучше, чем 422 «Ошибка при обработке сертификата» у Tizilim, который возвращается на любую неудачу подписи одинаково (kz-ecp-signing §6), — но не ждите, что он укажет на ваш дефект. Измерено 10.09.2026: и буквальная строка "not-a-signature", и корректный ГОСТ XMLDSig, сделанный просроченным тестовым сертификатом 2019 года из ЭСФ SDK, возвращаются как AUTH_ERROR_BAD_SIGNATURE, байт в байт. Код называет класс проблемы, а не то, что надо менять, так что дисциплина §6 «по одной переменной» здесь тоже в силе.

Каталог публичный, вход для него не нужен

Три CMS-маршрута отвечают вообще без токена — именно так код услуги превращается в название до того, как появилась сессия:

GET /v1/cms/passports?size=100&page=<n>   → 940 опубликованных записей, 635 различных кодов
GET /v1/cms/passports/popular             → десятка с главной, названия на kk/ru/en
GET /v1/cms/dictionaries/category-tree    → дерево, два корня: `fl` Гражданам, `ul` Бизнесу

У каждой записи есть service_code, title и category_breadcrumb вида ul.development.regAndClose. Две ловушки, обе измерены 10.09.2026:

  • Неизвестный параметр запроса игнорируется, а не отвергается. ?serviceCode=P3001 отвечает 200 и обычной первой страницей без всякого фильтра — а фильтр, который молча ничего не делает, неотличим от услуги, у которой честно одно совпадение. Работают size и page; limit, offset, pageSize и perPage — все из игнорируемых.
  • Неверный аргумент возвращается как 401. by-category принимает только categoryId: и ?category_id=…, и /by-category/<id> отвечают 401, что читается как проблема с правами и ею не является. И принимает он только второй уровень дерева — идентификатор третьего уровня даёт 404.

3. Вход по ЭЦП — три шага, и на третьем нужен человек

Шаг 1 — подписать константу

У этого портала нет шага «спроси у сервера документ». XML собирается клиентом и никогда не меняется:

<?xml version="1.0" encoding="UTF-8"?><login><client-type>PORTAL</client-type></login>

Это весь документ. Подписывается как enveloped XMLDSig авторизационным ключом (AUTH_RSA…, EKU OID 1.3.6.1.5.5.7.3.2). Запрос, который страница отдаёт NCALayer, дословно из бандла:

{
  "module": "kz.gov.pki.knca.basics",
  "method": "sign",
  "args": {
    "data": "<логин-XML выше>",
    "allowedStorages": ["PKCS12", "AKKaztokenStore", "AKKZIDCardStore"],
    "format": "xml",
    "signingParams": {},
    "signerParams": { "chain": undefined, "extKeyUsageOids": ["1.3.6.1.5.5.7.3.2"] },
    "locale": "ru"
  }
}

signingParams: {} — все значения по умолчанию: не декодировать, не оборачивать, не хешировать заранее, без TSA. chain заполняется только из NEXT_PUBLIC_PKI_ROOT_CHAIN_TEST, а это тестовая переменная: в проде страница цепочку не передаёт, значит и вам корни НУЦ РК подкладывать не надо.

Обратите внимание: это исключение из общей схемы. kz-ecp-signing §1 говорит, что документ строит сервер и собирать его самому не приходится; для ЭСФ и Tizilim это так, для входа на egov — нет. Для услуг egov — снова так, см. §4.

Шаг 2 — обменять подпись на сессию

POST /identity/v3/auth/eds        {"certificate": "<подписанный XML>"}
  → {"session_id": …, "is_ul": bool, "phone": "…"}

Шаг 3 — второй фактор, и обойти его нечем

Шаг 2 его уже отправил. Измерено 10.09.2026: SMS приходит от самого вызова /identity/v3/auth/eds — ничего дополнительно вызывать не нужно, и получить сессию, не побеспокоив владельца аккаунта, нельзя. (POST /identity/v3/auth/otp/send, принимающий session_id, — это кнопка «отправить повторно», а не первая отправка.) Учитывайте это: каждая попытка входа стоит клиенту одной SMS, так что /auth/eds — не проба, которую можно свободно повторять.

Клиент смотрит на is_ul и ветвится: юрлицо → SMS, физлицо → push в eGov Mobile. Дальше:

POST /identity/v3/auth/verify     → {"access_token": …, "refresh_token": …}
POST /identity/v3/auth/token/refresh   (продлевает; оба — JWT с iat/exp)

Ни SMS, ни push автоматизация не выдаст, поэтому человек участвует в каждом входе. Заложите это в проект, а не обнаруживайте при клиенте: держите refresh-токен и продлевайте сессию — тогда цена одно взаимодействие на время жизни токена, а не на каждое действие. Юрлицу и ИП код приходит по SMS на зарегистрированный телефон — из двух вариантов это тот, который проще организовать.


4. Заказ услуги — три вызова, и они одинаковы для всех 28

POST /v1/<SVC>/xml                → {xml, request_number, uuid, applicant_uin}
      подписать xml ПОДПИСНЫМ ключом            (EKU OID 1.3.6.1.5.5.7.3.4)
POST /v1/<SVC>/signing/send-eds   {"signed_xml": …, "request_number": …}
GET  /v1/<SVC>/request-status

Между входом и отправкой меняется запрашиваемое назначение. Вход просит EKU …3.2, заявление на услугу — EKU …3.4; это два явно разных вызова в одном бандле. kz-ecp-signing §3 предлагал такое разделение как догадку — на egov оно измерено.

Чего это больше не означает, так это двух файлов — и причина не та, о которой можно подумать.

10.09.2026 прочитано настоящее универсальное ГОСТ-свидетельство (ключ первого руководителя ТОО, выпущен в июне 2026). Его расширенное назначение — 1.3.6.1.5.5.7.3.4 плюс казахстанские OID 1.2.398.3.3.4.3.2, 1.2.398.3.3.4.1.2 и 1.2.398.3.3.4.1.2.1. 1.3.6.1.5.5.7.3.2 — тот самый OID, который просит вход этого портала, — отсутствует. И вход всё равно прошёл: 200 и session_id.

Значит extKeyUsageOids — это подборщик ключа для десктопа, а не правило, которое проверяет сервер: он говорит NCALayer, какой из файлов на диске предложить, а сервер проверяет подпись, а не заявленное назначение сертификата. Поэтому один универсальный ключ обслуживает оба шага, хотя clientAuth в нём не заявлен. Просите ключ — а если у клиента уцелела пара до 2024 года, обе её половины.

Ограничьте это честно. Измерено только на эндпоинте входа. Так же ли снисходителен /v1/<SVC>/signing/send-eds — не проверено, а Tizilim вполне может и не быть.

<SVC> — код государственной услуги. Такую тройку несут двадцать восемь кодов; публичный каталог из §2 даёт имя двадцати четырём из них:

КодУслугаРаздел портала
P3001Справки/сведения по юридическим лицамБизнесу · Регистрация
P3041Справка о наличии недвижимости (Форма-6) для юридических лицБизнесу · Недвижимость
P110Выдача выписок из лицевого счета о состоянии расчетов с бюджетомГражданам · Налоги
P305Справка о правах на недвижимость (Форма-2)Гражданам · Недвижимость
P3061Справка о наличии недвижимости (Форма-6) для физических лицГражданам · Недвижимость
P601Получение справки о пенсионных отчисленияхГражданам · Пенсии
P605Сервис получения информации о назначении пособий и пенсионных выплатГражданам · Пенсии
P608Получение справки о подтверждении инвалидностиГражданам · Соцобеспечение
P631Выдача справки по назначению АСПГражданам · Соцобеспечение
P640Выплаты по случаю потери работыГражданам · Занятость
P641Назначение АСПГражданам · Соцобеспечение
P703Прикрепление к поликлиникеГражданам · Ребенок
P704Справки из наркологии, психиатрии и тубдиспансераГражданам · Медицина
P714Выдача справки о временной нетрудоспособностиГражданам · Медицина
P1001Справка о несудимости (электронная)Гражданам · Трудоустройство
P1002Сведения о совершении лицом административного правонарушенияГражданам · Право
P1005Выдача сведений о совершении лицом коррупционного преступленияГражданам · Трудоустройство
P1902Добровольный отказ от получения банковских займов, микрокредитовГражданам · Кредитная история
P3006Предоставление сведений о зарегистрированном юрлице на заданную датуГражданам · Архив
P4005Сведения о регистрации в приграничной территорииГражданам · Регистрация
P4006Выдача удостоверения личности РКГражданам · Удостоверение
P6132Выплаты на рождение ребенкаГражданам · Ребенок
P6504Информация о статусе стипендиата международной стипендии «Болашак»Гражданам · Образование
P8001Информация о начислениях ЕНПФГражданам · Пенсии

Двадцать шесть из двадцати восьми — услуги для граждан. Под Бизнесу портал кладёт ровно две — P3001 и P3041. Это измерение; вывод, к которому оно подталкивает, такой: автоматизируемая поверхность egov — это в основном личные бумаги, и рабочего дня бухгалтера в ней нет. На краях, впрочем, читайте раздел свободно: P110 — выписка с лицевого счёта по налогам, лежит под Гражданам, а нужна ИП не меньше, чем человеку.

У четырёх кодов маршрутов нет опубликованного паспорта — P2203, P3002, P3005, P3011. P3001 — это группа, а не одна услуга (собственный бандл портала называет её P3001_GROUP_SEARCH_ORGANIZATIONS), и соседние P3003, P3004, P3006, P3007, P3008, P3010, P3013 опубликованы каждая отдельно — так что вероятнее всего эти четыре и есть шаги внутри группы. Это вывод, а не измерение.

Ничего из этого нельзя подготовить, пока человек не завершил вход. POST /v1/<SVC>/xml без bearer-токена отвечает 401 (измерено 10.09.2026), то есть собрать заявление заранее и получить SMS потом нельзя — человек идёт первым, всегда.

У некоторых услуг есть свои дополнительные чтения (/children-info, /guardiansover-info-by-guardian, справочники адресов); REG02 и REG06 — регистрационные потоки и устроены иначе.

accepted — это не готово. Опрашивайте request-status: то же правило, которому научил ЭСФ, где отправка отвечает успехом, а документ потом уходит в FAILED.


5. egov.kz — это ДВА портала, и новый API не видит старого

Это то, что нужно понять до того, как что-то обещать клиенту про его уже поданные дела.

НовыйСтарый
Фронтegov.kz (Next.js)my.egov.kz (AngularJS на JBoss)
APIfgw.egov.kz/v1/…my.egov.kz/one-inbox/rest-v2/…, /person-profile/rest-v2/…
АутентификацияAuthorization: Bearer из /identity/v3/auth/edscookie SSO от idp.egov.kz
Номер заявкиUUID (01a08c40-510e-70a1-…)целое число (764613146)

Дело, поданное через старый кабинет, невидимо для всего, что описано в этом документе. Измерено 10.09.2026 на живой сессии настоящего ТОО: заявление, которое клиент видел в my.egov.kz как одобренное, в истории нового портала не появилось вообще, его числовой номер вернул 404 из /v1/<SVC>/request-status, а bearer-токен нового API получил на my.egov.kz JBoss-овский 403. Два пространства идентификаторов, две сессии, моста нет.

То есть «проверь, прошло ли моё заявление» не решается bearer-токеном, если только заявление не подавалось через fgw. Старый ящик живёт за one-inbox/rest-v2/search/inbox и one-inbox/rest-v2/requests-history/, и попасть туда — это вход по ЭЦП на idp.egov.kz (kz-ecp-signing §5), а не тот, что в §3: поток с xmlToSign от сервера, который та страница и описывала до появления этой. Оба живы; это не альтернативы друг другу, это разные системы.

Собственная история нового портала

POST /dp/v3/status-notifications   {"limit": 1-100, "offset": n}
GET  /dp/v3/count-unread-notifications

limit обязателен, и его отсутствие — это 500, а не 400 (INVALID_ARGUMENT: Limit must be between 1 and 100, but was: 0): ошибка формы «инфраструктура упала» на пропущенный аргумент. Постраничность честная: has_more корректно переключается при разных offset, так что ей можно верить, а не вычитывать всё ради подсчёта.

POST /v1/<SVC>/xml — не локальный черновик, он регистрируется. Каждый вызов добавляет в эту ленту строку CREATED / «Заявка создана» и увеличивает счётчик непрочитанного — без всякой подписи и без send-eds. Ничего не подано, но клиент это видит. Не считайте первый из трёх вызовов пробным прогоном.


6. Чтения, которым нужна сессия, но не нужна подпись

Стоит знать, потому что они бесплатны и именно с них агенту следует начинать:

GET  /identity/v3/auth/user/info        → название и БИН юрлица
GET  /v1/P3001/organizations?bin=…      → запись реестра с названием (без адреса)
     …&name=… тоже работает; нужен один из bin/name, иначе 400
POST /v1/dp/personal-data               → запись вошедшего ЧЕЛОВЕКА

Две ловушки, измерены 10.09.2026. /v1/P3001/organizations возвращает названия организации и больше ничего — юридический адрес есть только в выданной справке, так что ответ на «какой адрес в реестре» требует эту справку реально заказать. А /v1/dp/* возвращает человека, а не организацию, даже внутри сессии с is_ul: true: сертификат первого руководителя несёт и ИИН, и БИН, поэтому кого из двоих имеет в виду маршрут — свойство маршрута, а не сессии.


7. Путь через QR — подпись вообще без ключа

Портал умеет подписывать вторым способом, при котором ключ не покидает телефон клиента:

POST /v1/push-sign                                          → запрос уходит в eGov Mobile
wss://fgw.egov.kz/v1/websocket/sign?request_number=…&uuid=…  → уведомление о подписании

Ответ /v1/<SVC>/xml уже содержит всё нужное (uuid, qr_url, xml_for_sign).

Это честный ответ клиенту, который не отдаст .p12, — и такая позиция разумна. Агент собирает заявление целиком, человек подтверждает его на телефоне. Цена — одно нажатие на каждое подписанное действие, и стоит прямо сказать, что так убирается набор данных, а не согласования.


8. Не водите этот портал браузером

Cloudflare-браузер работает в дата-центре; wss://127.0.0.1:13579 в нём — его loopback, а не клиентский. NCALayer оттуда недостижим, и Live View не помогает: Live View работает для паролей и OTP, потому что их набирают в странице, а ЭЦП отдаёт программа на машине человека.

Для потока выше это неважно — он весь обычный HTTP. Но «открой egov в браузере и войди ключом из моих файлов» — это ровно то, что клиент попробует сделать, поэтому будьте точны насчёт последствий: кнопка «Войти по ЭЦП» на странице просто зависает на попытке соединения. Внятной ошибки не будет. Войти за него можно — это §3, со стороны агента, — просто делает это не браузер.

Чтобы внести эту сессию в панель, нужен localStorage, а не cookie. Портал хранит сессию в zustand-хранилище с persist в localStorage (XLDAPR, msg_data), так что одними cookie не восстановится ничего. storageState у Playwright покрывает и то и другое, и restoreStorageState уже проигрывает localStorage по origin через init-скрипт рядом с cookie (apps/api/src/browser/browser-driver.service.ts). Чего сегодня нет — это возможности записать storage_state снаружи браузера: он только снимается с живого контекста. Пока этого нет, вход, сделанный агентом, в панель не передать.

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


9. Прежде чем что-то подписать

kz-ecp-signing §7 описывает обращение с ключом, и всё это в силе. Одно правило здесь жёстче, чем где-либо: заявление на egov — это юридически поданное обращение к государству от имени клиента. Соберите, покажите, спросите — и только потом подписывайте. Никогда не отправляйте send-eds по своей инициативе.


10. Что проверено, а что нет

Проверено на живой системе 10.09.2026 — базовый хост, все маршруты выше, константный логин-XML, оба EKU OID, и что API отвечает из-за пределов Казахстана без геоблокировки, капчи и CSRF-токена. /identity/v3/auth/eds вызывали дважды: мусорной строкой и настоящим enveloped ГОСТ XMLDSig логин-документа, сделанным Kalkan на OpenJDK 17 из публичного тестового ключа ЭСФ SDK. Оба ответа — 400 AUTH_ERROR_BAD_SIGNATURE, то есть транспорт, форма запроса и подписант работают; не проверено ровно одно — подпись, которую порталу есть за что принять.

Также проверено 10.09.2026 настоящим универсальным ГОСТ-ключом — enveloped XMLDSig логин-документа от Kalkan принимается (200, session_id, is_ul: true, телефон аккаунта в ответе), без NCALayer и без браузера. Сертификат при этом не несёт 1.3.6.1.5.5.7.3.2, и вход всё равно сработал (§4).

Также проверено 10.09.2026, вообще без учётных данных — публичный CMS-каталог (§2): 940 опубликованных паспортов на 635 различных кодов, дерево категорий из двух корней и названия для 24 из 28 автоматизируемых кодов услуг (§4). POST /v1/<SVC>/xml без авторизации отвечает 401, то есть собрать заявление до входа нельзя.

Вся цепочка входа проверена по состоянию на 10.09.2026. /auth/verify вернул 200 с access_token на 264 символа и refresh_token на 265, предъявлением кода из SMS, которую отправил сам /auth/eds. ЭЦП → Kalkan → сессия → SMS → токены, дважды, без NCALayer и без браузера. Дальше вживую ответили авторизованные чтения: user/info, P3001/organizations, dp/personal-data, dp/v3/status-notifications и P3001/xml (§5, §6).

Не проверено — отправка через send-eds, а значит и то, проверяет ли она EKU, который вход игнорирует; путь через QR дальше того факта, что /xml отдаёт qr_url; и вся сторона старого my.egov.kz, до которой ни одна полученная здесь сессия не дотягивается.