Веб-хуки
Веб-хуки позволяют церкви отправлять уведомления в реальном времени сторонним инструментам - платформам автоматизации (Zapier, Make, n8n), CRM, бухгалтерским системам или чему угодно, что принимает HTTP POST. Когда человек, группа или домохозяйство изменяются в B1, B1 отправляет подписанную JSON-полезную нагрузку на каждый URL, подписанный на это событие.
Прежде чем начать
- Администратор церкви с разрешением Редактировать настройки церкви регистрирует и управляет веб-хуками
- Ваша принимающая конечная точка должна быть доступна по HTTPS на публичном адресе
- Имейте способ безопасно хранить секрет подписи - он показывается только один раз
Обзор
Веб-хуки являются только исходящими: B1 вызывает вашу конечную точку, вы не вызываете B1. Каждый веб-хук представляет собой подписку для каждой церкви, состоящую из URL назначения, секрета подписи и списка подписанных событий.
Доставка использует надежный почтовый ящик: когда происходит подписанное событие, B1 записывает строку доставки, и фоновый воркер отправляет ее POST-запросом примерно в течение минуты. Неудачные доставки повторяются с экспоненциальной задержкой. Ничего не теряется, если доставка медленная или ваша конечная точка временно недоступна.
Регистрация веб-хука
В B1Admin
Перейдите в Настройки → Веб-хуки → Новый веб-хук. Введите имя, URL полезной нагрузки и выберите события для подписки. При сохранении секрет подписи отображается один раз - скопируйте его немедленно и сохраните его с вашей интеграцией. Он никогда не показывается снова (вы можете его ротировать позже, но вы не можете получить оригинал).
Через API
Все конечные точки находятся под базовым путем модуля Membership /membership/webhooks и требуют JWT от администратора церкви с разрешением Settings / Edit.
POST /membership/webhooks
Authorization: Bearer <jwt>
Content-Type: application/json
{
"name": "Zapier — новые члены",
"url": "https://hooks.zapier.com/hooks/catch/123/abc",
"events": ["person.created", "person.updated", "group.member.added"]
}
Ответ на создание - и только ответ на создание - включает secret:
{
"id": "a1b2c3d4e5f",
"name": "Zapier — новые члены",
"url": "https://hooks.zapier.com/hooks/catch/123/abc",
"events": ["person.created", "person.updated", "group.member.added"],
"active": true,
"secret": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822c"
}
| Метод и путь | Назначение |
|---|---|
GET /membership/webhooks | Список веб-хуков церкви (секрет опущен) |
GET /membership/webhooks/events | Каталог допустимых имен событий |
GET /membership/webhooks/:id | Загрузить один веб-хук |
POST /membership/webhooks | Создать (без id) или обновить (с id) |
POST /membership/webhooks/:id/regenerate-secret | Ротировать секрет подписи; возвращает новое значение один раз |
DELETE /membership/webhooks/:id | Удалить веб-хук |
GET /membership/webhooks/:id/deliveries | Последние попытки доставки для веб-хука |
GET /membership/webhooks/deliveries/:deliveryId | Полная полезная нагрузка и ответ для одной доставки |
POST /membership/webhooks/deliveries/:deliveryId/redeliver | Переставить доставку в очередь |
Каталог событий
Имена событий следуют шаблону {сущность}.{действие}. Получите актуальный список из GET /membership/webhooks/events.
| Событие | Срабатывает когда |
|---|---|
person.created | Добавлен человек |
person.updated | Изменена запись человека |
person.destroyed | Удален человек |
household.created | Добавлено домохозяйство |
household.updated | Изменено домохозяйство |
household.destroyed | Удалено домохозяйство |
group.created | Добавлена группа |
group.updated | Изменена группа |
group.destroyed | Удалена группа |
group.member.added | Человек добавлен в группу |
group.member.removed | Человек удален из группы |
Формат полезной нагрузки
Каждая доставка представляет собой HTTP POST с телом JSON и следующими заголовками:
| Заголовок | Описание |
|---|---|
Content-Type | Всегда application/json |
X-B1-Event | Имя события, например person.created |
X-B1-Delivery-Id | Уникальный идентификатор для этой попытки доставки - используйте его для дедупликации |
X-B1-Signature | Подпись HMAC-SHA256 необработанного тела (см. ниже) |
X-B1-Timestamp | Эпоха Unix в секундах, когда был отправлен запрос |
User-Agent | B1-Webhooks/1.0 |
Тело оборачивает измененный ресурс в небольшой конверт:
{
"event": "person.created",
"churchId": "AbC123XyZ90",
"occurredAt": "2026-05-17T14:32:08.114Z",
"data": {
"id": "Pq7Rs2Tu4Vw",
"churchId": "AbC123XyZ90",
"name": { "display": "Джордан Ривера", "first": "Джордан", "last": "Ривера" },
"contactInfo": { "email": "jordan@example.com" }
}
}
Для событий *.destroyed, data содержит только id и churchId удаленной записи.
Проверка подписей
Всегда проверяйте X-B1-Signature перед тем, как доверять полезной нагрузке. Подпись - это sha256=, за которым следует шестнадцатеричный HMAC-SHA256 необработанного тела запроса, ключом которого является ваш секрет подписи. Вычисляйте его по полученным байтам - не пересериализуйте разобранный JSON.
Node.js
const crypto = require("crypto");
function isValid(rawBody, signatureHeader, secret) {
const expected = "sha256=" + crypto.createHmac("sha256", secret).update(rawBody, "utf8").digest("hex");
const a = Buffer.from(expected);
const b = Buffer.from(signatureHeader || "");
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
Python
import hashlib, hmac
def is_valid(raw_body: bytes, signature_header: str, secret: str) -> bool:
expected = "sha256=" + hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature_header or "")
PHP
function isValid(string $rawBody, string $signatureHeader, string $secret): bool {
$expected = "sha256=" . hash_hmac("sha256", $rawBody, $secret);
return hash_equals($expected, $signatureHeader ?? "");
}
Отклоняйте любой запрос, подпись которого не совпадает. По желанию также отклоняйте запросы, чей X-B1-Timestamp старше нескольких минут, чтобы ограничить окна воспроизведения.
Доставка и повторы
Ваша конечная точка должна отвечать со статусом 2xx как можно быстрее - в идеале после того, как только поставила работу в очередь, а не после ее обработки. Любой не-2xx ответ, сбой соединения или ответ медленнее 10 секунд считается неудачной доставкой.
Неудачные доставки повторяются с экспоненциальной задержкой - 16 попыток примерно за 5 дней. Интервал растет от 1 минуты, через часы, до 3-дневных промежутков для последних попыток. После 16-й неудачной попытки доставка помечается как exhausted и прекращается.
Доставка как минимум один раз: доставка может прийти более одного раза (например, если ваша конечная точка преуспела, но ответ был потерян). Используйте заголовок X-B1-Delivery-Id для дедупликации - обрабатывайте каждый идентификатор только один раз и рассматривайте повторы как неоперации.
Автоматическое отключение
Если веб-хук производит три последовательные исчерпанные доставки, B1 автоматически отключает его. Исправьте вашу конечную точку, затем снова включите веб-хук в B1Admin (или через POST /membership/webhooks с "active": true).
Инспектирование и повторная доставка
Редактор веб-хуков в B1Admin показывает таблицу Последние доставки - событие, статус, количество попыток, код ответа и временная метка. Выбор строки раскрывает полную отправленную полезную нагрузку и полученный ответ.
Используйте Повторная доставка, чтобы переставить любую прошлую доставку в очередь с ее исходной полезной нагрузкой - полезно после исправления ошибки в вашей конечной точке или для заполнения событий, которые ваша конечная точка пропустила, пока она была недоступна.
Требования к URL
Поскольку URL веб-хуков предоставляются церковью, B1 применяет защиту от подделки запроса на стороне сервера. URL веб-хука отклоняется - при регистрации и перепроверяется перед каждой доставкой - если он:
- не использует
https - указывает на
localhost, имя хоста.local/.internal, или - разрешается в частный, обратный, локальный или облачный метаданные IP-адрес
Ваша конечная точка должна быть публично доступным HTTPS-сервисом.