enВойти в Senler

Доставка вебхуков

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

Основной раздел: Вебхуки.

Статистика доставки

Блок «Статистика вебхуков» объединяет доставку всех webhook приложения. В переключателе периода доступны 7, 30 и 90 дней.

Показатели разделяют принятые к доставке, доставленные, не доставленные, находящиеся в обработке и отмененные операции. «Попытки доставки» — это фактические HTTP-запросы, включая автоматические повторы и тестовые отправки. Поэтому попыток может быть больше, чем принятых событий.

События ошибок

Ошибка выполнения агента и ошибка отправки сообщения — независимые события. Чтобы отслеживать оба этапа, выберите error и message_undelivered. Автоматизация может вызывать агента или отправлять сообщение напрямую: в этих случаях применяются те же события.

В data событий error и message_undelivered передаются error_code, error_message и error_message_key, а также доступный контекст: agent_id, sender_type, sender_id, message_event_id, response_id, automation_id, version_id, run_id, task_id и node_id. message_event_id указывает на исходящее сообщение при ошибке отправки. Текст причины может отсутствовать: для программной обработки используйте error_code, а error_message_key обозначает ключ локализации ошибки агента. Внутренние трассировки и полные ответы ИИ-провайдера в событие не входят.

Событие automation_step_failed содержит в data идентификаторы automation_id, version_id, run_id, task_id, node_id, название шага node_name, а также error_code, error_message, occurred_at и retryable: false. Для шага отправки сообщения может присутствовать message_event_id. Общие dialog_id, lead_id и channel_id заполняются, если соответствующий контекст есть; автоматизация без диалога также может прислать это событие.

Промежуточные неудачные попытки, тестовые запуски и предусмотренный переход HTTP-шага по подключённой ветке «Ошибка» не вызывают automation_step_failed. Ошибка шага не означает остановку остальных параллельных веток. Один сбой может дать два разных события: например, message_undelivered и затем automation_step_failed, если из-за неудачной отправки завершился ошибкой шаг автоматизации. При повторной доставке одного события его event_id сохраняется; ручной повтор шага создаёт новую задачу и может привести к новому событию.

История и восстановление доставки

На странице webhook область «Запросы» показывает операции доставки в очереди, на повторе, завершенные успешно или завершенные с ошибкой. Для внутренних webhook также отображается понятный тип: вызов инструмента агентом или запуск шага автоматизации. Выберите операцию в списке, чтобы открыть её подробности.

История и восстановление доставки. Отмеченные элементы: 1. «Запросы»; 2. операцию
1. «Запросы» · 2. операцию

В фильтрах истории:

  • Введите полный task_id или event_id в поле идентификатора.
  • Нажмите кнопку поиска. Поиск по ID точный; содержимое JSON не сканируется.
  • Для дополнительных условий нажмите кнопку фильтров.
Вебхуки. Отмеченные элементы: 1. поле идентификатора; 2. кнопку поиска; 3. кнопку фильтров
1. поле идентификатора · 2. кнопку поиска · 3. кнопку фильтров

В открывшемся меню выберите нужные условия:

  • статус доставки;
  • состояние проблемы;
  • тип события.
Вебхуки. Отмеченные элементы: 4. статус доставки; 5. состояние проблемы; 6. тип события
4. статус доставки · 5. состояние проблемы · 6. тип события

Закройте меню, чтобы вернуться к панели поиска:

  • В переключателе периода выберите интервал от последних 24 часов до всего срока хранения.
  • Сбросьте фильтры, чтобы вернуться к исходной выборке.
  • При необходимости обновите список, чтобы получить текущие результаты.
Вебхуки. Отмеченные элементы: 7. переключателе периода; 8. Сбросьте фильтры; 9. обновите список
7. переключателе периода · 8. Сбросьте фильтры · 9. обновите список

Список догружается кнопкой «Показать еще».

Вебхуки. 1. «Показать еще»
1. «Показать еще»

Что требует внимания разработчика

В списке приложений у каждого приложения отдельно показываются два числа: сколько текущих инцидентов нужно проверить разработчику и сколько доставок не завершилось успешно за выбранный период. Это разные показатели. Историческая ошибка остаётся в статистике, даже если её уже рассмотрели, а счётчик «Проверить разработчику» содержит только нерешённые текущие инциденты. В API этот текущий счётчик возвращается как developer_attention вместе с соответствующим app_id.

Категория отвечает на вопрос, кто должен разбираться с причиной:

  • Ошибка приложения (application). Обработчик приложения вернул ошибку или сообщил о сбое своей логики. Разработчик приложения проверяет обработчик.
  • Настройка проекта (configuration). В установленном приложении конкретного проекта нет нужного аккаунта, доступа или другой настройки. Владелец или участник проекта исправляет настройку; это не ошибка кода приложения.
  • Ошибка платформы (platform). Запрос не дошёл до приложения из-за сбоя доставки внутри Senler. Причину устраняет Senler; разработчику приложения ничего перенастраивать не нужно.
  • Причина не определена (unknown). Ответа недостаточно для надёжной классификации. Разработчик проверяет запрос и ответ вручную.

application и unknown получают developer_action_required: true и входят в счётчик проверки разработчиком. configuration и platform получают developer_action_required: false и в этот счётчик не входят.

Как определяется категория

Senler классифицирует не по одному HTTP-коду и не по тексту ошибки. Используется следующий порядок:

  1. Если доставка завершилась до вызова внешнего обработчика, инцидент относится к platform.
  2. Если обработчик вернул корректный объект incident, Senler использует объявленную приложением категорию application или configuration.
  3. Если объекта incident нет, ответ 5xx считается application.
  4. Остальные необъяснённые ошибки считаются unknown.

Поле code не выбирает категорию автоматически. Это стабильный технический идентификатор причины внутри уже определённой категории. Поле retryable отдельно указывает, имеет ли смысл повторять запрос без исправления его данных. Для ответа без объекта incident значение выводится из результата доставки — сетевой ошибки, тайм-аута или HTTP-статуса. В истории запросов API возвращает итоговый incident с полями code, category, developer_action_required и retryable. У ручного повтора есть дополнительное исключение для ответов внешнего обработчика 401 и 403 — оно описано ниже.

Как приложению вернуть точную причину

Чтобы Senler не пытался угадать причину по HTTP-ответу, обработчик приложения может вернуть безопасный JSON с объектом incident. Например, инструмент оплаты не нашёл выбранный пользователем аккаунт в настройках проекта:

{
  "message": "Configured Prodamus account is unavailable",
  "incident": {
    "code": "prodamus_account_unavailable",
    "category": "configuration",
    "retryable": false
  }
}

Контракт объекта:

  • code — необязательный постоянный машинный код причины: от 1 до 128 символов, начинается с латинской буквы или цифры и далее содержит только строчные латинские буквы, цифры, ., _ или -; отсутствующий или некорректный код сохраняется как null, но не отменяет категорию;
  • category — только application или configuration; категории platform и unknown назначает сам Senler;
  • retryable — true, только если повтор того же payload без изменения данных действительно безопасен и может помочь;
  • developer_action_required приложение не передаёт — Senler вычисляет его по категории.

category и логическое значение retryable обязательны. Если одно из них отсутствует или недопустимо, Senler игнорирует объявленный объект и применяет обычную классификацию по источнику сбоя и HTTP-статусу.

Текст message нужен человеку, а incident.code — агенту, логам и автоматической диагностике. Не помещайте в них секреты, токены, персональные данные или внутренний stack trace. Если проблема вызвана выбранным аккаунтом или настройкой конкретной установки, используйте configuration; если сломана логика обработчика самого приложения — application.

Повтор и закрытие инцидента

В выбранной операции проверьте детали запроса: исходный JSON, HTTP-ответ или сетевую ошибку. Ниже находится список попыток с временем и результатом каждой доставки. Сначала устраните причину ошибки, затем выберите нужное действие:

  • «Отправить повторно» ещё раз отправляет сохранённый запрос на URL webhook. Ответ остаётся в журнале и сам по себе не продолжает работу ожидающего агента.
  • «Отправить повторно и передать ответ агенту» доступно для инструмента в режиме ожидания результата, если операция связана с агентом и её можно повторить. После успешного ответа результат передаётся ожидающему агенту для продолжения работы.
  • Если повтор не нужен, отметьте проблему решённой. Она исчезнет из числа нерешённых, но запрос не будет отправлен заново, а история сохранится.
История и восстановление доставки. Отмеченные элементы: 3. детали запроса; 4. «Отправить повторно»; 5. «Отправить повторно и передать ответ агенту»; 6. отметьте проблему решённой
3. детали запроса · 4. «Отправить повторно» · 5. «Отправить повторно и передать ответ агенту» · 6. отметьте проблему решённой

Повтор доступен только для ещё не решённой операции со статусом повтора или ошибки. Обычно требуется incident.retryable: true. Отдельное исключение — внешний обработчик ответил HTTP 401 или 403: после исправления авторизации или прав доступа запрос можно отправить вручную даже при retryable: false. Надпись «Автоматический повтор недоступен» не запрещает этот ручной повтор. Для ошибки внутри платформы исключение не действует.

Если кнопки повтора нет, исправьте данные или конфигурацию и заново выполните исходное действие. Это создаст запрос с актуальными данными. Ручная отправка из журнала не собирает параметры заново: она использует сохранённое тело запроса.

Перед подтверждением учтите защиту от дублей. Ручной повтор создаёт новую операцию доставки, но сохраняет исходный event_id; timestamp в теле обновляется, остальные данные остаются прежними. Автоматические попытки также сохраняют event_id, но обновляют timestamp тела и заголовка при каждой отправке. Поэтому на стороне обработчика определяйте дубли по event_id, а не по времени или полному совпадению JSON. Если действие уже выполнено, не создавайте заказ или сообщение повторно; для инструмента верните ранее полученный результат в ожидаемом формате.

Для нескольких нерешенных операций отметьте все загруженные или выберите строки вручную. Повторно отправить можно до 25 выбранных запросов за одно действие; каждый должен допускать ручной повтор. Для каждого создаётся отдельная операция с его исходным event_id. Отметить выбранные решенными можно для выборки до 100 запросов. Действие «Отметить решенными все по фильтру» обрабатывает до 1000 совпадений; если их больше, сузьте фильтр.

При закрытии выберите причину и оставьте комментарий от 10 до 1000 символов. Для обычной проверки используйте reviewed, если исправление не требовалось, или fixed, если причина устранена. Для специальных случаев доступны obsolete, superseded, invalid_payload, accepted_loss, task_completed, diagnostic_completed, replay_cancelled и webhook_deleted. Код причины сохраняется как resolution_code, комментарий — как resolution_comment; агент может использовать оба поля, чтобы отличить рассмотренный инцидент от действительно исправленного.

Операции хранятся 90 дней, нерешенные ошибки — до решения, а отдельные попытки доставки — 365 дней. Отметка «Решено» не удаляет историю и не отправляет запрос повторно; она только исключает проблему из числа нерешенных.

Если события не приходят

  1. Убедитесь, что webhook имеет статус «Активен» и нужный тип события отмечен.
  2. Запустите тест и проверьте последний HTTP-код и время вызова.
  3. Проверьте, что внешний URL доступен по HTTPS и отвечает в пределах тайм-аута: для публичного события и его теста это 60 секунд, для инструмента время задаётся в настройках инструмента.
  4. Убедитесь, что обработчик принимает Content-Type: application/json и служебный event_type: "test".
  5. Сверьте X-App-Id с Client ID приложения и X-Webhook-Event-Id с event_id в теле.
  6. Проверьте свежесть X-Webhook-Timestamp, его совпадение с timestamp тела и подпись тела запроса с единым секретом приложения по примеру проверки подписи.
  7. Откройте историю запросов и сопоставьте сохранённый payload, ответ или ошибку с журналом внешнего сервера по event_id.
  8. Возвращайте 2xx только после того, как событие принято или надёжно поставлено в вашу очередь; повторный event_id не обрабатывайте заново.
  9. Если секрет потерян, замените единый секрет и сразу обновите его во всех обработчиках приложения.