> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tungo.kz/llms.txt
> Use this file to discover all available pages before exploring further.

# Получать события (вебхуки)

> Добавьте адрес своего сервера, выберите события, проверьте подпись и подготовьтесь к повторам и дублям.

Вебхук избавляет от опроса API: когда в организации что-то происходит, Tungo сам присылает POST-запрос с JSON на адрес вашего сервера. Вы добавляете адрес, выбираете события и получаете секрет, которым проверяете подпись каждого запроса.

Адреса добавляет владелец или администратор организации на экранах платформы. То же можно сделать по API ключом с правом `webhooks.manage`, оно есть только у ключа на все компании.

Не путайте вебхуки с входящими хуками автоматизаций. Вебхук — это событие от Tungo к вам. Входящий хук — это событие от вашей системы к Tungo, которое запускает сценарий: см. [Автоматизации](https://docs.tungo.kz/automations/overview.md).

## Добавить адрес

**1. Откройте «Вебхуки»**

В меню кабинета нажмите **Платформа**, выберите раздел **Вебхуки** и нажмите **Добавить адрес**.

**2. Укажите адрес сервера**

Подойдёт только адрес, который начинается с `https://` и доступен из интернета. Адреса внутренней сети Tungo не принимает.

**3. Выберите события**

Отметьте события, которые нужны этому адресу. Если не выбрать ничего, будут приходить все.

**4. Скопируйте секрет подписи**

После добавления экран показывает секрет вида `whsec_…`. Сохраните его на своём сервере как пароль.

Тот же адрес по API:

```sh theme={null}
curl -X POST "$TUNGO_API/v1/workspaces/$WS/webhooks/endpoints" \
  -H "x-api-key: $TUNGO_KEY" -H "Content-Type: application/json" \
  -d '{"url":"https://example.kz/tungo-events","event_types":["proposal.written"]}'
```

В ответе придут `id` адреса и `secret`. По ключу секрет больше нигде не прочитать, его можно только сменить. В кабинете секрет можно посмотреть позже: меню адреса, пункт **Показать секрет**.

## Какие события бывают

Имена событий передаются в поле `event_types` и приходят в поле `type`.

* Документы для 1С: `proposal.awaiting_approval`, `proposal.written`, `proposal.failed`, `proposal.rejected`.
* Ответы ИИ-бухгалтера по ключу: `chat.turn.completed`.
* Разбор выписок и ЭСФ: `bank_statement.received`, `esf.incoming.received`, `batch.completed`, `batch.failed`.
* Автоматизации: `automation.run.completed`, `automation.run.failed`, `automation.run.notice`, `automation.write_unknown`.
* Баланс платформы: `platform.balance_low`, `platform.balance_exhausted`, `platform.cap_threshold_reached`.
* Ключи: `api_key.expiring`, `api_key.cap_reached`.
* Оплата и связь с 1С: `payment.succeeded`, `payment.failed`, `onec.connection.changed`.

Тело у всех событий устроено одинаково:

```json theme={null}
{
  "id": "evt_…",
  "type": "proposal.written",
  "created_at": "…",
  "workspace_id": "ws_…",
  "company_id": "co_…",
  "data": {}
}
```

В `data` лежат только id, суммы в тиынах, статусы и время. Имён, реквизитов и текста документов там нет. За подробностями обращайтесь к API по id из события. Поля `data` каждого события описаны в справочнике API и на вкладке «Виды событий» в разделе «Вебхуки».

Адресу можно задать ещё и `channels` — список id сценариев. Тогда на него приходят только события этих сценариев, например итог одного сценария в свою систему. Это поле доступно только через API.

## Отправить пробное событие

В меню адреса выберите **Проверочная отправка**. На адрес уйдёт событие с типом `ping` и пустым `data`. Оно подписано так же, как настоящие, поэтому на нём удобно проверить и приём, и подпись. Итог смотрите в пункте **Попытки доставки**: там видно, что ответил ваш сервер.

По API пробное событие отправляет `POST /v1/workspaces/{ws}/webhooks/endpoints/{id}/test`.

## Проверить подпись

Каждый запрос приходит с тремя заголовками: `webhook-id`, `webhook-timestamp` и `webhook-signature`. Проверяйте подпись до того, как что-либо делать с событием. Иначе любой, кто узнал адрес, сможет прислать вам поддельное.

Подписывается строка из трёх частей через точку: `webhook-id`, `webhook-timestamp` и тело запроса. Тело берётся ровно в том виде, в каком пришло, до разбора JSON. Ключ подписи — это часть секрета после `whsec_`, раскодированная из base64. Подпись считается как HMAC-SHA256 и кодируется в base64.

```js theme={null}
import { createHmac, timingSafeEqual } from 'node:crypto'

// secret — whsec_…; headers — заголовки запроса; rawBody — тело строкой, как пришло, до разбора JSON.
function verifyWebhook(secret, headers, rawBody, nowSec = Date.now() / 1000) {
  const id = headers['webhook-id']
  const ts = headers['webhook-timestamp']
  if (Math.abs(nowSec - Number(ts)) > 300) return false // старше 5 минут: повтор чужого запроса
  const key = Buffer.from(secret.slice('whsec_'.length), 'base64')
  const want = createHmac('sha256', key).update(`${id}.${ts}.${rawBody}`).digest()
  // В заголовке подписи через пробел: v1,<base64>. После смены секрета их две.
  return headers['webhook-signature'].split(' ').some((s) => {
    const got = Buffer.from(s.split(',')[1] ?? '', 'base64')
    return got.length === want.length && timingSafeEqual(got, want)
  })
}
```

Если подпись не сошлась, отвечайте 400 и ничего не делайте. Подпись соответствует открытому соглашению Standard Webhooks, поэтому вместо своего кода можно взять готовую библиотеку, например `standardwebhooks` из npm.

Секрет меняется пунктом **Перевыпустить секрет** в меню адреса или запросом `POST …/endpoints/{id}/secret/rotate`. Ещё сутки после смены Tungo ставит в заголовок две подписи, новым и прежним секретом. Приёмник, который проверяет «совпала хотя бы одна», как в примере выше, переживёт смену без потери событий.

## Повторы и дубли

Доставка считается удачной, если ваш сервер ответил любым кодом 2xx за 30 секунд. Поэтому отвечайте сразу, а долгую обработку делайте после ответа.

Если ответа нет или он другой, Tungo повторяет отправку: через 5 секунд, 5 минут, 30 минут, 2 часа, 5 часов, потом шесть раз через 10 часов и ещё раз через 5 часов. Всего получается 13 попыток примерно за трое суток. После этого событие можно отправить вручную: вкладка «События», пункт **Отправить ещё раз**.

Из-за повторов одно событие может прийти дважды. У повтора тот же `id` в теле, по нему и отбрасывайте дубли. Порядок тоже не гарантируется: события могут прийти не в той последовательности, в какой случились. Сверяйте `created_at`, а актуальное состояние читайте через API.

## Если адрес не отвечает

Адрес, который пять суток подряд не принял ни одного события, Tungo выключает сам. В списке у него состояние «Выключен», новые события на него не отправляются. Почините приёмник и включите адрес: меню адреса, пункт **Включить**, или запрос `PATCH` с `"enabled": true`.

Не рассчитывайте, что события, которые случились, пока адрес был выключен, придут сами. Восстановите пропущенное через API: прочитайте очередь документов, запуски автоматизаций или расход за этот период.

## Что дальше

* [Ошибки и ограничения](https://docs.tungo.kz/platform/errors-and-limits.md): что отвечает API, когда запрос не проходит.
* [Автоматизации](https://docs.tungo.kz/automations/overview.md): сценарии, о запусках которых сообщают события `automation.*`.
* [Баланс платформы и расход](https://docs.tungo.kz/platform/balance.md): события о низком балансе и как на них реагировать.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.