Отслеживание статусов подписания
После отправки документа на подпись нужно отслеживать его прогресс. HRlink не поддерживает webhooks — интегратор сам опрашивает API (стратегия polling).
Что получится в конце
После настройки polling интеграция будет получать изменения статусов документов, определять завершённые и отклонённые документы и сохранять дату последней успешной синхронизации.
Что нужно заранее
| Что нужно | Где получить |
|---|---|
tenantHost | Адрес тенантаTenant Экземпляр системы HRlink на отдельном домене (например, company.hr-link.ru). Внутри одного тенанта может быть несколько пространств клиентов. HRlink |
clientId | Текущий пользователь |
| Токен | Аутентификация |
documentId или externalId | Из ответа на создание документа или из внешней системы |
| Права на документы | Авторизация и права доступа |
Поле lastSyncAt | Храните на стороне интеграции для инкрементального polling |
Какие методы используются
| Сценарий | Метод |
|---|---|
| Проверить один документ | Получить документ |
| Проверить документ по внешнему IDexternalId Внешний идентификатор сущности — произвольная строка, задаваемая интегратором при создании. Связывает сущность HRlink с записью во внешней системе (1С, SAP и др.) без хранения маппинга UUID. | Получить документ по externalId |
| Получать изменения пачками | Получить реестр документов |
| Остановить подписание | Прервать подписание документа |
| Аннулировать подписанный документ | Аннулировать документ |
Способы получения статуса
1. Получить конкретный документ
- curl
- PowerShell
- HTTP
curl -X GET "https://{tenantHost}/api/v1/clients/{clientId}/documents/{documentId}" \
-H "Accept: application/json" \
-H "User-Api-Token: {token}"
Invoke-RestMethod `
-Method GET `
-Uri "https://{tenantHost}/api/v1/clients/{clientId}/documents/{documentId}" `
-Headers @{
"Accept" = "application/json"
"User-Api-Token" = "{token}"
}
GET /api/v1/clients/{clientId}/documents/{documentId} HTTP/1.1
Host: {tenantHost}
Accept: application/json
User-Api-Token: {token}
2. Реестр документов кадровика
- curl
- PowerShell
- HTTP
curl -X POST "https://{tenantHost}/api/v1/clients/{clientId}/documents/hrRegistry" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "User-Api-Token: {token}" \
-d '{
"legalEntityIds": ["{UUID юрлица}"],
"limit": 50,
"offset": 0
}'
$body = @{
legalEntityIds = @("{UUID юрлица}")
limit = 50
offset = 0
} | ConvertTo-Json
Invoke-RestMethod `
-Method POST `
-Uri "https://{tenantHost}/api/v1/clients/{clientId}/documents/hrRegistry" `
-Headers @{
"Accept" = "application/json"
"User-Api-Token" = "{token}"
} `
-ContentType "application/json" `
-Body $body
POST /api/v1/clients/{clientId}/documents/hrRegistry HTTP/1.1
Host: {tenantHost}
Accept: application/json
Content-Type: application/json
User-Api-Token: {token}
{
"legalEntityIds": ["{UUID юрлица}"],
"limit": 50,
"offset": 0
}
Основные фильтры реестра:
| Поле | Назначение |
|---|---|
legalEntityIds | Фильтр по юрлицам |
documentTypeIds | Фильтр по типам документов |
documentStatuses | Фильтр по статусам документов (DocumentStatus) |
documentDateFrom / documentDateTo | Диапазон дат самих документов (поле date документа) |
createdDateFrom / createdDateTo | Диапазон дат создания документа в HRlink |
statusLastModifiedDateFrom / statusLastModifiedDateTo | Диапазон дат последнего изменения статуса — ключевое поле для инкрементального polling |
employeeIds | Фильтр по сотрудникам-подписантам |
baseDocumentExternalIds | Фильтр по externalIdexternalId Внешний идентификатор сущности — произвольная строка, задаваемая интегратором при создании. Связывает сущность HRlink с записью во внешней системе (1С, SAP и др.) без хранения маппинга UUID. черновика (для работы с размножением документов) |
Полный список фильтров — в OpenAPI-спецификации.
Статусы документа
Значения enum DocumentStatus:
| Статус | Описание |
|---|---|
DRAFT | Черновик — ожидает отправки на подписание |
IN_PROCESS | Документ в процессе подписания (ожидает действий участников) |
AWAITING_MY_SIGNING | Документ ожидает подписания текущим пользователем |
COMPLETED | Подписание завершено на всех этапах маршрута |
REJECTED | Отклонён одним из участников |
ANNULLED | Аннулирован |
DELETED | Удалён |
Определение статуса по маршруту
Детали прогресса подписания — в поле route документа:
{
"route": {
"stages": [
{
"id": "0d07668b-4e28-40a7-b25f-7a5a2a0a3b4c",
"indexNumber": 0,
"type": "SIGNING",
"completenessCondition": "ALL",
"participants": [
{
"id": "9a35f510-9a7c-4f2f-b5a3-8a8f87170f22",
"type": "EMPLOYEE",
"actionType": "SIGNING",
"signedDate": "2025-01-16T10:30:00Z",
"rejectedDate": null,
"seenDate": "2025-01-16T10:25:00Z"
}
]
},
{
"id": "07b8b2fa-7cf7-4d4a-a01e-fb110044c5ef",
"indexNumber": 1,
"type": "SIGNING",
"participants": [
{
"id": "74c60239-d6f5-42f8-bf56-cfb680600415",
"type": "EMPLOYER",
"actionType": "SIGNING",
"signedDate": null,
"rejectedDate": null,
"seenDate": null
}
]
}
]
}
}
Как читать данные маршрута
Для каждого участника (route.stages[n].participants[m]):
| Поле | Значение | Что означает |
|---|---|---|
signedDate | не null | Участник подписал |
rejectedDate | не null | Участник отклонил |
seenDate | не null | Участник просмотрел документ |
| Все null | — | Участник ещё не получил документ или не принял решение |
Логика определения текущего состояния
Стратегия polling
Выбор паттерна зависит от задачи. Два сценария:
- Short polling — ждать конкретный документ после отправки (минуты)
- Incremental polling — отслеживать изменения по всему реестру (часы, дни, постоянно)
Short polling: конкретный документ
Сценарий: только что отправили документ и хотите дождаться, пока он перейдёт в COMPLETED или REJECTED. Вызывайте Получить документ или Получить документ по externalId.
| Параметр | Значение |
|---|---|
| Первый опрос | Через 30-60 секунд после отправки (время на конвертацию в PDF/A) |
| Стартовый интервал | 10-15 секунд |
| Увеличение интервала | Экспоненциальное (×1.5), с jitter ±20% |
| Максимальный интервал | 5 минут |
| Общий таймаут | Зависит от бизнес-процесса — обычно срок подписания (deadlineDate) плюс запас. Для автоподписания — минуты; для маршрутов с человеком — часы или дни |
| При 429 | Экспоненциальный backoff, согласно Ограничениям |
Короткий polling — это подстраховка для случаев, когда нужно немедленно среагировать на финальный статус. Для долгого ожидания решений человека переключайтесь на incremental polling.
Incremental polling: изменения по реестру
Сценарий: у вас тысячи документов и нужно подтягивать изменения статусов в вашу систему. Вызывайте Получить реестр документов с фильтром statusLastModifiedDateFrom.
Алгоритм:
- Сохраните
lastSyncAt= момент начала предыдущего опроса (по часам вашей системы, UTC). - Перед опросом запомните
currentSyncAt = now(). - Вызовите реестр с
statusLastModifiedDateFrom = lastSyncAt - ε, гдеε— небольшой буфер (например, 30 секунд) против рассинхрона часов и событий на границе. - При необходимости пройдите по страницам через
offset/limit, пока выдача не кончится. - После успешной обработки всей страницы сохраните
lastSyncAt = currentSyncAt.
| Параметр | Значение |
|---|---|
| Интервал между циклами | 1-5 минут для активных процессов, 15-30 минут для архивных |
limit на страницу | 50 (дефолт) или меньше — для снижения нагрузки на один запрос |
Буфер ε перекрытия | 30-60 секунд — защита от граничных событий между запросами |
| Фильтры | Всегда задавайте legalEntityIds и по возможности documentStatuses, чтобы сузить выборку |
| При 429 | Пропустите цикл, увеличьте интервал до следующего — согласно Ограничениям |
Не удаляйте буфер ε — без него при рассогласовании часов серверов можно пропустить изменение, произошедшее в момент запроса.
При реестрах больше 45 000 документов разбивайте запросы по юрлицам и временным окнам. Без фильтров сервер отвечает медленнее — растёт риск таймаутов и перегрузки интеграции.
Пример incremental polling
Запрос документов, у которых статус изменился с момента последнего опроса.
- curl
- PowerShell
- HTTP
curl -X POST "https://{tenantHost}/api/v1/clients/{clientId}/documents/hrRegistry" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "User-Api-Token: {token}" \
-d '{
"legalEntityIds": ["{UUID юрлица}"],
"statusLastModifiedDateFrom": "2025-01-15T12:00:00Z",
"documentStatuses": ["COMPLETED", "REJECTED", "ANNULLED"],
"limit": 50,
"offset": 0
}'
$body = @{
legalEntityIds = @("{UUID юрлица}")
statusLastModifiedDateFrom = "2025-01-15T12:00:00Z"
documentStatuses = @("COMPLETED", "REJECTED", "ANNULLED")
limit = 50
offset = 0
} | ConvertTo-Json
Invoke-RestMethod `
-Method POST `
-Uri "https://{tenantHost}/api/v1/clients/{clientId}/documents/hrRegistry" `
-Headers @{
"Accept" = "application/json"
"User-Api-Token" = "{token}"
} `
-ContentType "application/json" `
-Body $body
POST /api/v1/clients/{clientId}/documents/hrRegistry HTTP/1.1
Host: {tenantHost}
Accept: application/json
Content-Type: application/json
User-Api-Token: {token}
{
"legalEntityIds": ["{UUID юрлица}"],
"statusLastModifiedDateFrom": "2025-01-15T12:00:00Z",
"documentStatuses": ["COMPLETED", "REJECTED", "ANNULLED"],
"limit": 50,
"offset": 0
}
Аннулирование документа
Если документ нужно отозвать после отправки на подпись:
- curl
- PowerShell
- HTTP
curl -X POST "https://{tenantHost}/api/v1/clients/{clientId}/documents/{documentId}/annul" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "User-Api-Token: {token}" \
-d '{
"reason": "Документ оформлен с ошибкой"
}'
$body = @{
reason = "Документ оформлен с ошибкой"
} | ConvertTo-Json
Invoke-RestMethod `
-Method POST `
-Uri "https://{tenantHost}/api/v1/clients/{clientId}/documents/{documentId}/annul" `
-Headers @{
"Accept" = "application/json"
"User-Api-Token" = "{token}"
} `
-ContentType "application/json" `
-Body $body
POST /api/v1/clients/{clientId}/documents/{documentId}/annul HTTP/1.1
Host: {tenantHost}
Accept: application/json
Content-Type: application/json
User-Api-Token: {token}
{
"reason": "Документ оформлен с ошибкой"
}
Прерывание подписания
Для прерывания процесса подписания (без аннулирования):
- curl
- PowerShell
- HTTP
curl -X POST "https://{tenantHost}/api/v1/clients/{clientId}/documents/{documentId}/sign/interrupt" \
-H "Accept: application/json" \
-H "User-Api-Token: {token}"
Invoke-RestMethod `
-Method POST `
-Uri "https://{tenantHost}/api/v1/clients/{clientId}/documents/{documentId}/sign/interrupt" `
-Headers @{
"Accept" = "application/json"
"User-Api-Token" = "{token}"
}
POST /api/v1/clients/{clientId}/documents/{documentId}/sign/interrupt HTTP/1.1
Host: {tenantHost}
Accept: application/json
User-Api-Token: {token}
- Аннулирование — документ становится недействительным, нельзя продолжить подписание
- Прерывание — процесс подписания останавливается, но документ можно отправить заново