Подписки на события (Webhooks)
Система позволяет внешним сервисам (Odoo, боты) получать уведомления о событиях через HTTP-вызовы.
Как подписаться
Создайте подписку, указав URL и список событий. В ответе придёт secret — ключ для проверки подлинности. Сохраните его, повторно получить нельзя.
Техническое описание
Паттерны событий
При создании подписки можно указать конкретные события или паттерны:
| Паттерн | Что получите |
|---|---|
property.delisted |
Только делистинг |
property.transition.* |
Все переходы статусов |
property.* |
Все property-события (создание, переходы, модерация, делистинг) |
mls.* |
Листинг и делистинг с MLS |
contact_request.* |
Запросы контакта через MLS |
* |
Все события |
Какие события существуют
| Событие | Когда срабатывает | Что содержит |
|---|---|---|
property.created |
Создан новый объект | property_id, tenant_id |
property.transition.{action} |
Переход статуса (approve, delist, ...) | property_id, action, from/to status |
property.delisted |
Объект снят с MLS | property_id, tenant_id, from_status_id, from_status_name |
property.moderation_required |
Объект отправлен на проверку (→ in_review) | property_id, tenant_id |
mls.new_listing |
Объект появился на MLS (→ approved/assigned) | property_id, tenant_id |
mls.listing_removed |
Объект убран с MLS | property_id, tenant_id |
contact_request.received |
Кто-то запросил контакт через MLS | property_id, requester_tenant_id, owner_tenant_id |
tenant.subscription_expiring |
Подписка тенанта истекает через 7 дней | tenant_id, expires_at |
Пример payload делистинга
{
"event_id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"event_type": "property.delisted",
"timestamp": "2026-02-16T12:00:00+00:00",
"data": {
"event_id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"event_type": "property.delisted",
"property_id": 40,
"tenant_id": 1,
"from_status_id": 3,
"from_status_name": "legal_check",
"timestamp": "2026-02-16T12:00:00+00:00"
}
}
Проверка подлинности (HMAC)
Каждый webhook-вызов подписывается ключом secret из подписки. Заголовок X-EstateKit-Signature содержит подпись sha256=<hex>.
import hashlib, hmac
def verify(body: bytes, secret: str, signature: str) -> bool:
expected = hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature.removeprefix("sha256="))
Заголовки webhook-вызова
| Заголовок | Описание |
|---|---|
X-EstateKit-Event |
Тип события |
X-EstateKit-Signature |
HMAC-SHA256 подпись |
X-EstateKit-Delivery-Id |
UUID для дедупликации |
X-EstateKit-Timestamp |
Unix timestamp отправки |
Повторные попытки
- При ошибке (HTTP 5xx, timeout, connection error) — повторная доставка
- Интервалы: 2с, 4с, 8с, 16с, ... до 1 часа (exponential backoff)
- Максимум 10 попыток
- После 10 неудач подписка автоматически деактивируется
- Успех: любой HTTP 2xx ответ
Идемпотентность
Каждое событие содержит уникальный event_id. Клиент должен сохранять обработанные ID и пропускать дубликаты. Заголовок X-EstateKit-Delivery-Id — тот же UUID.
Прямое подключение к RabbitMQ
Альтернатива webhooks — подключение напрямую к RabbitMQ (exchange estate_kit.events, topic). Routing keys:
property.created,property.transition.approve,property.delistedmls.new_listing,mls.listing_removedcontact_request.received#— все события