Перейти к основному содержанию
Когда правило Firewall возвращает вердикт pending_approval, шлюз удерживает вызов инструмента и уведомляет вашу собственную систему подтверждений вне основного канала. Это уведомление — подписанный HTTP POST, полезная нагрузка вебхука firewall, и эта страница документирует её точную форму, чтобы вы могли проверить подпись, маршрутизировать событие и запостить своё решение обратно. Это асинхронный собрат in-console потока подтверждений, описанного на странице Firewall. Консольный путь (ревьюер кликает approve/reject) не нуждается в вебхуке вообще. Вебхук — для случая, когда вы хотите, чтобы машина — ваш собственный тикетинг-бот, Slack-действие или рантайм агента — разрешила удержание. Оба пути first-writer-wins, так что вы можете запускать их бок о бок.
Вебхук — это best-effort сигнал маршрутизации, а не авторитетный HITL-канал. Собственный long-poll агента на GET /api/v1/firewall/approvals/:id — это подстраховка: если уведомление потеряно или ваш эндпоинт ненадолго лежит, удержанный вызов всё равно появляется в консоли и разрешается нормально. Вебхук просто позволяет машине среагировать быстрее, чем это сделал бы человек.

1. Полезная нагрузка вебхука firewall с первого взгляда

OrcaRouter POST’ит JSON-конверт на URL, который вы настраиваете, подписанный общим секретом. Вот полная доставка — заголовки и тело:
POST /your-approval-endpoint HTTP/1.1
Content-Type: application/json
X-Orca-Event: firewall.approval.pending
X-Orca-Signature: sha256=9f86d0818988...c2c9a3e1b4d7

{
  "event": "firewall.approval.pending",
  "workspace_id": 42,
  "occurred_at": "2026-06-09T12:00:00.123456789Z",
  "data": {
    "approval_id": "665f1a2b3c4d5e6f7a8b9c0d",
    "tool_name": "db.export",
    "request_id": "req_01J9X...",
    "conversation_id": "conv_8f2a...",
    "policy_id": 7,
    "rule_id": 31
  }
}
Конверт имеет ту же форму, что OrcaRouter использует для каждого подписанного события, так что один приёмник может маршрутизировать много типов событий по X-Orca-Event, не парся тело.

2. Поля конверта

Всегда firewall.approval.pending для удержания подтверждения. Зеркалится в заголовке X-Orca-Event, так что вы можете маршрутизировать до парсинга тела.
Целочисленный id рабочего пространства, чья политика удержала вызов. Полезно, когда один эндпоинт получает вебхуки от нескольких рабочих пространств.
Timestamp RFC 3339 / UTC (наносекундная точность) для момента, когда шлюз поставил подтверждение в очередь. Парсится любым стандартным событийным инструментарием.
Блок, который нужен вашему колбэку, чтобы разрешить гейт. Поля в §3.

3. Полезная нагрузка data

Блок data несёт всё нужное для маршрутизации и разрешения удержания — намеренно без аргументов инструмента. Вебхук — сигнал маршрутизации; полный контекст вызова (инструмент, аргументы, сработавшее правило) живёт на консольной вкладке Approvals и в журнале аудита, где он защищён доступом.
ПолеТипЗначение
approval_idstringId, против которого вы постите своё решение.
tool_namestringУдержанный инструмент, например db.export.
request_idstringRelay-запрос, который вызвал удержание.
conversation_idstringId диалога / сессии агента.
policy_idintПолитика firewall, которая совпала.
rule_idintПравило, вернувшее pending_approval.
Нужны аргументы или совпавшая клауза, чтобы принять решение? Прочитайте их с консольной вкладки Approvals (Developer+) или пусть ваш агент опросит GET /api/v1/firewall/approvals/:id своим токеном шлюза. Вебхук намеренно никогда не несёт аргументы по проводу.

4. Проверка подписи

Каждая доставка подписана, так что вы можете отклонять подделки. Заголовок подписи:
X-Orca-Signature: sha256=<hex HMAC-SHA256(secret, raw_body)>
где secret — секрет вебхука подтверждений, который вы задали на рабочем пространстве, а raw_bodyточные байты тела запроса. Вычислите HMAC по сырым байтам — повторная сериализация распарсенного JSON изменит пробелы и сломает сравнение. Проверяйте за постоянное время:
import hmac, hashlib

def verify(raw_body: bytes, header: str, secret: str) -> bool:
    expected = "sha256=" + hmac.new(
        secret.encode(), raw_body, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, header)
Подпись исходящего вебхука покрывает только тело. Входящий колбэк, который вы постите обратно (§6), подписывает approval_id + перевод строки + тело — другая конструкция, намеренно, так что захваченная подпись не может быть переиграна между подтверждениями. Не переиспользуйте одну подписывающую рутину для обоих направлений.

5. Настройка вебхука

URL назначения и общий секрет — настройки рабочего пространства; задайте их один раз в консоли (или через settings API; Developer+). Нет участия оператора и нечего деплоить.
1

Задайте URL и секрет

В настройках Firewall задайте ваш HTTPS-эндпоинт как URL вебхука подтверждений и сильный общий секрет. URL должен быть https:// — plaintext-назначения отклоняются — а секрет write-only (он никогда не возвращается при чтении; ответ настроек сообщает только, задан ли он).
2

Создайте правило pending_approval

Добавьте правило Firewall, чей вердикт — pending_approval (или используйте пресет HITL). См. Правила Firewall.
3

Получите и проверьте

Ваш эндпоинт получает подписанный POST на следующем удержанном вызове. Проверьте подпись (§4), затем либо разрешите через колбэк, либо покажите её человеку.
Удержанный вызов всё равно работает без настроенного вебхука — он просто показывается в консоли для разрешения человеком. И если вы задали URL, но не секрет, шлюз пропускает диспетч целиком, потому что эндпоинт колбэка принимает только подписанные запросы: уведомление, которое вы не смогли бы аутентифицировать в ответ, было бы бесполезным.

6. Колбэк: разрешение удержания

Чтобы одобрить или отклонить машиной, запостите обратно на:
POST /api/v1/firewall/approvals/:id/callback
с тем же :id, что вы получили как approval_id, подписанным тем же общим секретом. Тело — это решение:
BODY='{"decision":"approved","reason":"ticket OPS-4821 approved by on-call"}'
SIG="sha256=$(printf '%s\n%s' "$APPROVAL_ID" "$BODY" \
  | openssl dgst -sha256 -hmac "$SECRET" -hex | sed 's/^.* //')"

curl https://api.orcarouter.ai/api/v1/firewall/approvals/$APPROVAL_ID/callback \
  -H "Content-Type: application/json" \
  -H "X-Orca-Signature: $SIG" \
  -d "$BODY"
Поле телаОбязательноЗначения
decisionдаapproved или rejected
reasonнетСвободная заметка, записывается в журнал аудита.
Решение approved пропускает следующую попытку агента один раз — агент переотправляет исходный вызов с одноразовым заголовком X-OrcaRouter-Firewall-Approval. Решение rejected оставляет вызов заблокированным.
Разрешение идемпотентно и first-writer-wins. Если человек уже разрешил удержание из консоли — или приходит дублирующий колбэк — эндпоинт возвращает 200 с already_resolved: true, и исходное решение остаётся в силе. Безопасно повторять.

7. Состояния подтверждения

Удержанный вызов проходит через эти состояния; ваш колбэк управляет переходом из pending:
СостояниеЗначение
pendingОжидает решения (состояние на момент вебхука).
approvedРазрешено — закрытый гейтом вызов может пройти один раз.
rejectedРазрешено — закрытый гейтом вызов остаётся заблокированным.
expiredУдержание устарело без решения.

8. Сопутствующие справочники

Firewall — поток HITL

Как pending_approval удерживает вызов, и агент переотправляет с одноразовым заголовком подтверждения.

Коды ошибок

firewall_approval_pending и другие HTTP-ответы firewall.

Глоссарий вердиктов

Каждый вердикт firewall, включая pending_approval.

Firewall API

Полный справочник консольных маршрутов + маршрутов шлюза.
О том, как удержания вписываются в более широкую модель управления, см. Режимы применения и Опасные вызовы инструментов.