API и вебхуки
REST API с JSON и подписанные вебхуки позволяют вашим системам создавать заявки, получать их состояние и реагировать на принятые решения.
Аутентификация и токены
- Откройте Настройки → API в вашей организации (доступно администраторам).
- Создайте токен и сразу скопируйте — он показывается только один раз.
- Передавайте его в каждом запросе в заголовке:
Authorization: Bearer <token>.
Токены принадлежат организации, а не конкретному пользователю, и отзываются в любой момент. В организации может быть до 20 активных токенов и до 60 вызовов API в минуту.
API
Все методы доступны по адресу https://approvehub.ru/api/v1 и обмениваются данными в формате JSON.
Процессы подробно
GET /api/v1/workflows/ возвращает список процессов организации с постраничной навигацией: ?page=N (по 10 на страницу) и фильтрами ?status=published и ?status=unpublished. Ответ содержит workflows, page и total_count. Для каждого процесса возвращаются id, slug, name, description, status, version и даты.
POST /api/v1/workflows/ принимает обязательное поле name и необязательные поля slug, description, publish, requesters, access, fields и stages. Типы полей: text, long_text, email, url, phone, number, date, time, date_range, checkbox, select, radio, file, money, user_select, calculated; у каждого типа свой объект settings. Этап состоит из групп. Тип группы может быть "any" (достаточно одного согласования) или "all" (нужны все), а согласующие задаются по id или email участников организации. Значение "publish": true сразу открывает процесс для заявок. Для публикации процесс должен содержать хотя бы одно поле.
У этапа может быть skip_when — список наборов условий для проверки данных отправленной формы. Если полностью выполняется хотя бы один набор, этап согласуется автоматически без участия согласующих. Набор имеет вид {"match": "all"|"any", "rules": [...]}, наборы объединяются по «или», а условие — {"field": "<слаг поля>", "operator": "…", "values": ["…"]}. Операторы с одним операндом используют первый элемент values, а для filled и empty значение не требуется. Этап может содержать не более 5 наборов, а каждый набор — не более 10 условий.
Доступные операторы зависят от типа поля: текстовые поля принимают equals, not_equals, contains, not_contains, starts_with, ends_with; number, date и time — equals, not_equals, greater, greater_or_equal, less, less_or_equal; date_range — starts_before, starts_after, ends_before, ends_after, longer_than, shorter_than; select и radio — equals, not_equals, any_of, none_of; checkbox — any_of, all_of, none_of; для file количество вложений сравнивается с помощью equals, greater, less; money принимает equals, not_equals, greater, greater_or_equal, less, less_or_equal со значением из двух частей — суммы и валюты — и срабатывает только при совпадении валюты ответа; user_select принимает any_of, all_of, none_of с id участников. Вычисляемые поля нельзя использовать в условиях. Для остальных типов также доступны filled и empty. Даты передаются как YYYY-MM-DD, время — как HH:MM, а сравниваемые варианты должны существовать в настройках поля.
При успешном создании сервер отвечает кодом 201 и возвращает полный процесс, включая созданный slug, слаги полей для передачи значений и id этапов и полей. GET /api/v1/workflows/{id}/ возвращает данные в том же формате, а PUT /api/v1/workflows/{id}/ принимает такое же тело, как запрос создания, и позволяет опубликовать процесс. version обозначает версию процесса, по которой созданы заявки, и меняется только при редактировании формы или цепочки согласования. revision увеличивается при каждом сохранении, в том числе при переименовании. Передайте полученный revision в PUT: если процесс уже изменил другой пользователь, сервер отклонит сохранение с кодом 400. Без revision сохраненные данные будут перезаписаны:
Заявки подробно
GET /api/v1/requests/ возвращает список заявок организации от новых к старым. Доступны постраничная навигация ?page=N (по 20 заявок на страницу) и фильтры ?workflow=<slug>, ?status=new|in_progress|completed|declined, ?requester=<email участника>. Ответ содержит requests, page и total_count.
POST /api/v1/requests/ создает заявку: workflow — слаг процесса, fields — значения по слагам полей. Обязательные поля должны присутствовать, неизвестные слаги отклоняются.
Формат значения зависит от типа поля:
text,long_text,email,url,phone,select,radio,dateиtimeпринимают строку (даты —YYYY-MM-DD).numberпринимает число.checkboxпринимает массив значений выбранных опций.date_rangeпринимает{"from": "…", "to": "…"}.fileпринимает массивidзагруженных файлов (см. «Файлы» ниже).moneyпринимает{"amount": "123.45", "currency": "USD"}— сумма передается десятичной строкой, валюта — одним из разрешенных кодов поля.user_selectпринимает массив id участников вида["<uuid>"]— каждый должен быть активным участником с разрешенной для поля ролью; поле с одиночным выбором принимает не больше одного id.calculatedне принимает значение: его передача приведет к ошибке. Объектsettingsсодержитexpression, например"Итого: {{amount}} + {{tax}}". Выражение вычисляется по другим полям сразу при заполнении формы и при каждом получении заявки; флагhidden_for_requesterскрывает результат от заявителя. Выражение ссылается на другие поля по идентификатору (slug), не может ссылаться на другое вычисляемое поле и ограничено 500 символами и 10 подстановками.
При создании сервер отвечает кодом 201 и возвращает полную заявку; GET /api/v1/requests/{id}/ позднее возвращает данные в том же формате. stage — этап, на котором заявка ожидает решения; после завершения заявки он отсутствует. fields содержат отправленные значения, а массив decisions пополняется с каждым решением. Поле action принимает "accept" или "decline":
POST /api/v1/requests/{id}/decisions/ записывает решение от имени администратора, выпустившего токен. Администратор должен быть согласующим текущего этапа. Поле action принимает "approve" или "reject"; для reject обязателен comment. В ответе возвращается обновленная заявка. Повторное решение или попытка принять решение вне своей очереди возвращает код 400.
Файлы
POST /api/v1/files/ принимает multipart-форму с единственным полем file (до 20 МБ) и отвечает кодом 201 с данными загруженного файла. Передайте его id в поле типа file при создании заявки. Файлы, не прикрепленные ни к одной заявке, удаляются через сутки.
В ответе по заявке каждое поле типа file возвращает файлы объектами: id совпадает с id загрузки, name — исходное имя файла, а по url можно скачать сам файл с тем же bearer-токеном. Скачивание доступно только участникам, которым видна заявка, — остальным вернется 404.
Ошибки
Каждая ошибка — JSON с полем error; ошибки валидации добавляют details по полям в том виде, в котором вы их отправили:
Коды: 400 — некорректные данные, 401 — токен отсутствует или отозван, 403 — владельцу токена недоступно действие с ресурсом, подписка заблокирована либо исчерпан лимит заявок, 404 — ресурс с таким id не существует или недоступен, 429 — превышен лимит запросов, 5xx — ошибка на нашей стороне; такой запрос можно повторить.
Вебхуки
Добавьте адрес вебхука в разделе Настройки → API. События по заявкам организации будут поступать на него в виде подписанных POST-запросов с JSON. Сразу после добавления мы отправим событие ping, чтобы проверить подключение.
Все события имеют общую структуру: event, request_id, workflow (слаг), status заявки после события, сведения об исполнителе действия и occurred_at (RFC 3339, UTC). Данные пользователя передаются как {id, name}; адрес электронной почты в теле события отсутствует.
ping
Отправляется один раз сразу после добавления вебхука, чтобы проверить адрес и подпись до отправки рабочих событий:
request.submitted
В процесс поступила новая заявка. requested_by — тот, кто ее создал:
request.stage_completed
Этап получил необходимое количество согласований, и заявка перешла дальше. stage — только что завершенный этап, decided_by — согласующий, чье решение завершило его. Для последнего этапа это событие не отправляется; вместо него приходит request.approved:
request.approved
После согласования последнего этапа заявка получает положительное решение:
request.rejected
Согласующий отклонил заявку. Поле comment содержит причину отклонения:
Проверка доставок
Каждая доставка содержит имя события, время Unix и HMAC-подпись:
Вычислите подпись с помощью секрета вебхука, времени и исходного тела запроса, затем сравните ее со значением заголовка:
Сравнивайте за константное время и отбрасывайте устаревшие временные метки, чтобы исключить повторную отправку.
Повторные попытки и автоматическое отключение
Если обработчик не отвечает вовремя или возвращает код вне диапазона 2xx, доставка повторяется до 8 раз с увеличивающейся задержкой: от одной до 30 минут. Ответьте в течение 10 секунд, а длительную обработку выполняйте после отправки ответа.
После 20 неудачных попыток подряд вебхук отключается, а администраторы организации получают письмо. Когда обработчик снова заработает, включите вебхук в разделе Настройки → API.