Webhook API
Webhook API — это способ отправки уведомлений в Notix с вашего сервера (бэкенд, CRM, интеграция). Один POST-запрос с токеном и подписью — и уведомление появляется в личном кабинете.
Вебхук — только для серверных интеграций
JavaScript SDK на сайте ходит не сюда, а в свой канал /api/v1/sdk/ingest, привязанный к домену сайта (SDK-токен публичный, поэтому вебхук его не принимает). Вебхук-токен — серверный секрет: его нельзя светить в браузерном коде.
Эндпоинт
POST /api/v1/webhookАутентификация
Токен передаётся в заголовке Authorization в формате Bearer:
Authorization: Bearer ntx_xxxxxxxxxxxxxxxxxxxxxxxxТокен создаётся в личном кабинете при подключении источника «Webhook». Формат токена всегда начинается с префикса ntx_.
Заголовки запроса
| Заголовок | Обязательно | Описание |
|---|---|---|
| Authorization | Да | Bearer-токен: Bearer ntx_... |
| Content-Type | Да | application/json |
| X-Notix-Signature | Да* | HMAC-подпись тела запроса: sha256=<hex>. Обязательна, если при создании источника выдан секрет подписи (whsec_...) — см. ниже |
Безопасность
Вебхук защищён тремя уровнями: токен + привязка к домену/IP + HMAC-подпись. Даже узнав адрес, посторонний не сможет отправлять уведомления от вашего имени.
1. Привязка к домену и IP
При создании webhook-источника укажите адрес вашего сервера (домен). Notix резолвит его A/AAAA-записи и принимает запросы только с этих IP. Чужой сервер с тем же токеном получит 403 IP not allowed. Если IP сервера сменился (переезд, новый хостинг) — обновите адрес источника или пересоздайте токен.
2. Подпись запроса (HMAC)
При создании источника выдаётся секрет подписи whsec_... (показывается один раз — сохраните его). Каждый запрос подписывается: HMAC-SHA256 от сырого JSON-тела с этим секретом, результат — в заголовок X-Notix-Signature: sha256=<hex>.
BODY='{"title":"Новый заказ #1247","notification_type":"order"}'
SECRET='whsec_xxxxxxxxxxxxxxxxxxxxxxxx'
SIGNATURE=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$SECRET" | awk '{print $2}')
curl -X POST https://notix-hub.ru/api/v1/webhook \
-H "Authorization: Bearer ntx_..." \
-H "Content-Type: application/json" \
-H "X-Notix-Signature: sha256=$SIGNATURE" \
-d "$BODY"<?php
$token = 'ntx_...';
$secret = 'whsec_...';
$body = json_encode([
'title' => 'Новый заказ #1247',
'notification_type' => 'order',
], JSON_UNESCAPED_UNICODE);
// Подпись считается от ТОЙ ЖЕ строки, что уходит в тело запроса
$signature = 'sha256=' . hash_hmac('sha256', $body, $secret);
$ch = curl_init('https://notix-hub.ru/api/v1/webhook');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer ' . $token,
'Content-Type: application/json',
'X-Notix-Signature: ' . $signature,
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
echo curl_exec($ch);import crypto from 'node:crypto';
const token = 'ntx_...';
const secret = 'whsec_...';
const body = JSON.stringify({
title: 'Новый заказ #1247',
notification_type: 'order',
});
// Подпись от той же строки, что отправляется в body
const signature = 'sha256=' +
crypto.createHmac('sha256', secret).update(body).digest('hex');
const response = await fetch('https://notix-hub.ru/api/v1/webhook', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
'X-Notix-Signature': signature,
},
body,
});
console.log(await response.json());Важно про подпись
Подпись считается от байт-в-байту того же JSON, который отправляется (сериализуйте один раз и используйте строку и для подписи, и для тела). Если библиотека формирует тело сама — подпись не сойдётся и запрос будет отклонён с 401 Invalid signature.
Тело запроса
| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
| title | string | Да | Заголовок уведомления (макс. 255 символов) |
| body | string | Нет | Текст уведомления |
| notification_type | string | Нет | Slug типа: lead, order, event, metric, error_batch. Подробнее о типах |
| priority | string | Нет | Приоритет: low, normal, high, urgent |
| push | boolean | Нет | Отправлять ли push-уведомление на телефон. По умолчанию true. Установите false чтобы только записать в ленту без push |
| tag | string | Нет | Одиночный тег (строка). Если нет в БД — создастся с цветом по умолчанию #10B981 |
| tags | string[] | object[] | Нет | Массив: строки или {name, color?}. Чтобы задать цвет — передайте объект |
| payload | object | Нет | Произвольный JSON |
Как работают теги
При первой отправке укажите объект с name и color — тег создастся с этим цветом:
"tags": ["простая строка", {"name":"Важное","color":"#EF4444"}]При повторной отправке тег с таким именем уже существует — цвет сохраняется (не перезаписывается). Можно передавать просто строку:
"tags": ["Важное"] // цвет останется #EF4444Если тега нет и передан только цвет — создастся с цветом по умолчанию #10B981.
Примеры
curl -X POST https://notix-hub.ru/api/v1/webhook \
-H "Authorization: Bearer ntx_live_x8k2jp9mQr5vLwY3aN6bHc1d" \
-H "Content-Type: application/json" \
-d '{
"title": "Новый заказ #1247",
"body": "Клиент: Иванов И.И.\nСумма: 34 500 ₽",
"notification_type": "order",
"priority": "high",
"push": true,
"tags": ["заказ", {"name":"оплата","color":"#10B981"}]
}'<?php
$token = 'ntx_live_x8k2jp9mQr5vLwY3aN6bHc1d';
$data = [
'title' => 'Новый заказ #1247',
'body' => "Клиент: Иванов И.И.\nСумма: 34 500 ₽",
'notification_type' => 'order',
'priority' => 'high',
];
$ch = curl_init('https://notix-hub.ru/api/v1/webhook');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer ' . $token,
'Content-Type: application/json',
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
echo $response;import requests
token = "ntx_live_x8k2jp9mQr5vLwY3aN6bHc1d"
data = {
"title": "Новый заказ #1247",
"body": "Клиент: Иванов И.И.\nСумма: 34 500 ₽",
"notification_type": "order",
"priority": "high",
}
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json",
}
response = requests.post(
"https://notix-hub.ru/api/v1/webhook",
json=data,
headers=headers,
)
print(response.json())const token = 'ntx_live_x8k2jp9mQr5vLwY3aN6bHc1d';
const response = await fetch('https://notix-hub.ru/api/v1/webhook', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
title: 'Новый заказ #1247',
body: 'Клиент: Иванов И.И.\nСумма: 34 500 ₽',
notification_type: 'order',
priority: 'high',
}),
});
const result = await response.json();
console.log(result);import java.net.URI;
import java.net.http.*;
var token = "ntx_live_x8k2jp9mQr5vLwY3aN6bHc1d";
var json = """
{
"title": "Новый заказ #1247",
"body": "Клиент: Иванов И.И.\\nСумма: 34 500 ₽",
"notification_type": "order",
"priority": "high"
}
""";
var request = HttpRequest.newBuilder()
.uri(URI.create("https://notix-hub.ru/api/v1/webhook"))
.header("Authorization", "Bearer " + token)
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(json))
.build();
var response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());var token = "ntx_live_x8k2jp9mQr5vLwY3aN6bHc1d";
var data = new
{
title = "Новый заказ #1247",
body = "Клиент: Иванов И.И.\nСумма: 34 500 ₽",
notification_type = "order",
priority = "high"
};
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post,
"https://notix-hub.ru/api/v1/webhook");
request.Headers.Add("Authorization", "Bearer " + token);
request.Content = new StringContent(
System.Text.Json.JsonSerializer.Serialize(data),
System.Text.Encoding.UTF8,
"application/json"
);
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);Ответы
| Код | Описание |
|---|---|
| 201 Created | Уведомление создано. {"message":"Notification received","id":"..."} |
| 401 Unauthorized | Токен недействителен/истёк, либо неверная подпись (Invalid signature) |
| 403 Forbidden | Запрос с неразрешённого IP (IP not allowed) или попытка использовать SDK/chat-токен в вебхуке |
| 402 Payment Required | Исчерпан лимит уведомлений тарифа |
| 422 Unprocessable | Ошибка валидации: неверный payload, отсутствуют обязательные поля |
Примеры по типам уведомлений
Заявка (lead) — cURL
curl -X POST https://notix-hub.ru/api/v1/webhook \
-H "Authorization: Bearer ntx_..." \
-H "Content-Type: application/json" \
-d '{
"title": "Новая заявка с лендинга",
"body": "Заявка на консультацию",
"notification_type": "lead",
"priority": "high",
"push": true,
"tags": ["лендинг"],
"payload": {
"name": "Иван Петров",
"phone": "+7 917 000-00-00",
"email": "ivan@example.com"
}
}'Заказ (order) — cURL
curl -X POST https://notix-hub.ru/api/v1/webhook \
-H "Authorization: Bearer ntx_..." \
-H "Content-Type: application/json" \
-d '{
"title": "Новый заказ #1247",
"body": "Заказ оформлен через сайт",
"notification_type": "order",
"priority": "high",
"tags": ["заказ"],
"payload": {
"fname": "Иван Петров",
"phone": "+7 917 000-00-00",
"order_id": "1247",
"items": [
{"name": "Футболка", "price": 2500, "qty": 2},
{"name": "Кроссовки", "price": 7000, "qty": 1}
],
"address": "г. Москва, ул. Ленина, 15",
"location": "https://shop.ru/orders/1247"
}
}'Событие (event) — cURL
curl -X POST https://notix-hub.ru/api/v1/webhook \
-H "Authorization: Bearer ntx_..." \
-H "Content-Type: application/json" \
-d '{
"title": "Обновление склада",
"body": "Товар перемещён",
"notification_type": "event",
"priority": "normal",
"push": false,
"payload": {
"event_code": "warehouse_update",
"event_title": "Обновление склада",
"properties": [
{"title": "Склад", "value": "Коледино"},
{"title": "Товар", "value": "Футболка мужская"},
{"title": "Количество", "value": "120 шт."}
]
}
}'Без push-уведомления
Флаг push (boolean) управляет отправкой push на телефон. По умолчанию true. Для «тихих» уведомлений (только в ленту) укажите "push": false.
Перегенерация токена
Если токен был скомпрометирован, его можно перегенерировать в личном кабинете. Старый токен перестаёт работать немедленно.