Ontik → ваша система

Доставьте событие в свою автоматизацию

Webhook запускает ваш обработчик после создания нового события в Ontik. Например, форма передаёт заявку в Ontik, команда получает Web Push, а ваш обработчик создаёт запись в CRM.

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

Что это даёт

  • Передача заявки в CRM по вашим правилам.
  • Создание задачи во внутренней системе или запись события в вашу БД.
  • Запуск собственного сценария обработки или отправки уведомлений.

Готовых адаптеров CRM, мессенджеров и трекеров задач в MVP нет: обработчик размещаете вы и подключаете API нужной системы.

Направление и момент отправки

Источник → API Ontik → новое событие → Webhook → ваш обработчик. Для входящих сигналов мониторинга используется REST API. Webhook вызывается при создании события; изменения статуса не являются отдельными webhook-событиями в текущей реализации.

Подключение в кабинете

  1. Разместите обработчик по публичному HTTPS-адресу, например https://example.ru/webhook.
  2. Откройте проект → «API и интеграция» → «Webhooks».
  3. Добавьте адрес и сразу сохраните секрет whsec_…: он показывается один раз.
  4. Передайте секрет обработчику через переменную окружения ONTIK_WEBHOOK_SECRET.
  5. Создайте событие через форму или API. В кабинете раскройте «Последние доставки» и проверьте статус.

Локальные и приватные адреса блокируются вне режима разработки. Примеры ниже слушают только 127.0.0.1:9000: для реальной доставки опубликуйте путь через HTTPS вашего сервера. Один локальный URL в кабинете не сделает обработчик доступным из интернета.

Запрос от Ontik

POST /webhook
Content-Type: application/json
X-Ontik-Signature: sha256=<HMAC подпись>

{"event_id":"a730caf5-2c37-4191-a232-7b2a12789869","event":"Новая заявка","meta":{"request_id":"REQ-1048"},"created_at":"2026-10-20T08:44:56.051425+00:00"}

event_id — ID исходного события, event — заголовок, meta — контекст, created_at — время создания. Подпись — HMAC-SHA256 от исходных байтов тела. Повторная сериализация JSON для проверки подписи не подходит.

Готовый обработчик: Python

Нужен Python 3; внешние пакеты не требуются. Сохраните код в receiver.py.

import hashlib, hmac, json, os
from http.server import BaseHTTPRequestHandler, HTTPServer

SECRET = os.environ["ONTIK_WEBHOOK_SECRET"].encode("utf-8")

class Handler(BaseHTTPRequestHandler):
    def do_POST(self):
        if self.path != "/webhook":
            self.send_error(404)
            return
        size = int(self.headers.get("Content-Length", "0"))
        if not 0 < size <= 65536:
            self.send_error(413)
            return
        body = self.rfile.read(size)
        signature = self.headers.get("X-Ontik-Signature", "")
        expected = "sha256=" + hmac.new(SECRET, body, hashlib.sha256).hexdigest()
        if not hmac.compare_digest(expected, signature):
            self.send_error(401)
            return
        try:
            event = json.loads(body)
            event_id = event["event_id"]
        except (ValueError, KeyError, TypeError):
            self.send_error(400)
            return
        # Здесь сохраните событие/задачу с уникальным event_id в своей БД.
        print("Accepted event:", event_id)
        self.send_response(200)
        self.end_headers()
        self.wfile.write(b"OK")

HTTPServer(("127.0.0.1", 9000), Handler).serve_forever()

Выберите свою платформу. Код Python остаётся одним и тем же; отличаются команды запуска и переменные окружения.

Windows · PowerShell

$env:ONTIK_WEBHOOK_SECRET = "whsec_СЕКРЕТ_ИЗ_КАБИНЕТА"
python receiver.py

Linux · Bash

export ONTIK_WEBHOOK_SECRET="whsec_СЕКРЕТ_ИЗ_КАБИНЕТА"
python3 receiver.py

macOS · Zsh / Bash

export ONTIK_WEBHOOK_SECRET="whsec_СЕКРЕТ_ИЗ_КАБИНЕТА"
python3 receiver.py

Готовый обработчик: Node.js

Нужен Node.js 18 или новее. Сохраните код в receiver.mjs. Установка npm-пакетов не требуется.

import http from "node:http";
import { createHmac, timingSafeEqual } from "node:crypto";

const secret = process.env.ONTIK_WEBHOOK_SECRET;
if (!secret) throw new Error("Set ONTIK_WEBHOOK_SECRET");

const server = http.createServer(async (req, res) => {
  if (req.method !== "POST" || req.url !== "/webhook") {
    res.writeHead(404).end();
    return;
  }
  try {
    const chunks = [];
    let size = 0;
    for await (const chunk of req) {
      size += chunk.length;
      if (size > 65536) { res.writeHead(413).end(); return; }
      chunks.push(chunk);
    }
    const rawBody = Buffer.concat(chunks);
    const expected = Buffer.from("sha256=" +
      createHmac("sha256", secret).update(rawBody).digest("hex"));
    const received = Buffer.from(req.headers["x-ontik-signature"] ?? "");
    if (received.length !== expected.length ||
        !timingSafeEqual(expected, received)) {
      res.writeHead(401).end();
      return;
    }
    const event = JSON.parse(rawBody.toString("utf8"));
    if (!event.event_id) { res.writeHead(400).end(); return; }
    // Сохраните задачу в БД с уникальным event_id перед ответом 200.
    console.log("Accepted event:", event.event_id);
    res.writeHead(200).end("OK");
  } catch {
    res.writeHead(400).end();
  }
});
server.requestTimeout = 15000;
server.listen(9000, "127.0.0.1");

Выберите свою платформу. Код Python остаётся одним и тем же; отличаются команды запуска и переменные окружения.

Windows · PowerShell

$env:ONTIK_WEBHOOK_SECRET = "whsec_СЕКРЕТ_ИЗ_КАБИНЕТА"
node receiver.mjs

Linux · Bash

export ONTIK_WEBHOOK_SECRET="whsec_СЕКРЕТ_ИЗ_КАБИНЕТА"
node receiver.mjs

macOS · Zsh / Bash

export ONTIK_WEBHOOK_SECRET="whsec_СЕКРЕТ_ИЗ_КАБИНЕТА"
node receiver.mjs

Проверка без подключения Ontik

Запустите один обработчик. Во втором терминале установите такой же секрет и выполните этот Python-код. Он отправляет подписанный учебный запрос только вашему локальному обработчику.

import hashlib, hmac, json, os, urllib.request
body = json.dumps({"event_id": "local-test-001", "event": "Учебный тест",
                   "meta": {}, "created_at": "2026-10-22T00:00:00+00:00"},
                  ensure_ascii=False).encode("utf-8")
signature = "sha256=" + hmac.new(os.environ["ONTIK_WEBHOOK_SECRET"].encode(),
                               body, hashlib.sha256).hexdigest()
request = urllib.request.Request("http://127.0.0.1:9000/webhook", data=body,
    headers={"Content-Type": "application/json", "X-Ontik-Signature": signature})
with urllib.request.urlopen(request, timeout=5) as response:
    print(response.status)

Ожидается 200 у клиента и Accepted event: local-test-001 у обработчика. Запрос без подписи или с другим секретом должен получить 401.

Повторы и журнал

В текущем worker — до 8 попыток, тайм-аут запроса 15 секунд, повторы с увеличением задержки. Успешный ответ — 2xx. При сбое возможна повторная доставка одного события: перед выполнением бизнес-действия фиксируйте event_id в БД с уникальным ограничением.

Обработчики выше демонстрируют приём и проверку подписи, выводя только ID. Для CRM добавьте сохранение задачи и защиту от дублей. Изменение внешней CRM не должно повторяться из-за повторной доставки.

В кабинете видны последние 20 доставок в раскрываемом журнале. Срок хранения журнала по умолчанию — 30 дней; он настраивается оператором.