API и вебхуки
REST API поверх JSON и подписанные вебхуки: ваши системы могут создавать заявки, читать их состояние и реагировать сразу после решения. API в бете — детали еще могут меняться, но мы предупредим до того, как что-то сломается.
Аутентификация и токены
- Откройте Настройки → API в вашей организации (доступно администраторам).
- Создайте токен и сразу скопируйте — он показывается только один раз.
- Передавайте его в каждом запросе в заголовке:
Authorization: Bearer <token>.
Токены принадлежат организации, а не человеку, и отзываются в любой момент. В организации может быть до 20 активных токенов и до 60 вызовов API в минуту.
API
Все методы живут под https://approvehub.app/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 — у каждого свой объект 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. У любого типа есть еще 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, если процесс тем временем изменил кто-то другой; без него запись перезапишет то, что сохранено:
Заявки подробно
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загруженных файлов (см. «Файлы» ниже).
Создание отвечает 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-поле при создании заявки — загрузки, не прикрепленные ни к одной заявке, исчезают через сутки.
Ошибки
Каждая ошибка — JSON с полем error; ошибки валидации добавляют details по полям в том виде, в котором вы их отправили:
Коды: 400 — некорректный ввод, 401 — токен отсутствует или отозван, 403 — владельцу токена нельзя действовать с ресурсом либо подписка заблокирована или исчерпан лимит заявок, 404 — чужой или неизвестный id, 429 — превышен rate limit, 5xx — проблема на нашей стороне, такие запросы повторяйте.
Вебхуки
Добавьте адрес вебхука в Настройках → API — и каждое событие заявок организации будет приходить туда подписанным JSON POST-запросом. Сразу после добавления мы отправляем ping, чтобы вы проверили связку.
У доставок общий вид: event, request_id, workflow (слаг), status заявки после события, кто действовал и occurred_at (RFC 3339, UTC). Люди приходят как {id, name} — email-адресов в payload нет.
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.