Перейти до вмісту

Підписана доставка

Спочатку перевірте. Усуньте дублікати до побічних ефектів.

Webhooks є сповіщеннями в межах застосунку, а не джерелом доступу до tenant. Отримувач має автентифікувати необроблене тіло запиту, перевірити актуальність і атомарно зберегти id події.

Контракт доставки

ЧастинаКонтракт
Подіїbooking.confirmed, booking.cancelled, booking.reschedule_requested, booking.rescheduled, booking.updated
ЗаголовкиX-Fenix-Event-Id, X-Fenix-Delivery-Id, X-Fenix-Timestamp, X-Fenix-Signature та Idempotency-Key
Назви сумісностіX-Fenix-*, data-fenix-* і FENIX_* є стабільними успадкованими назвами протоколу. Зберігайте їх без змін у наявних інтеграціях.
Підписv1=<HMAC-SHA256(timestamp + "." + raw_body)> з одноразовим секретом whsec_
АктуальністьПриймайте лише п’ятихвилинне вікно timestamp і відхиляйте некоректні version/type/reference конверта.
Повторні спробиП’ять обмежених спроб із затримками 1m, 5m, 30m і 2h. 2xx завершує доставку; 3xx відхиляється без переходу.

Мінімальний потік перевірки

js
import { createHmac, timingSafeEqual } from 'node:crypto';

const rawBody = await request.text();
const timestamp = request.headers.get('x-fenix-timestamp') || '';
const signature = request.headers.get('x-fenix-signature') || '';
const ageSeconds = Math.abs(Date.now() - Number(timestamp) * 1000) / 1000;
const expected = 'v1=' + createHmac('sha256', process.env.FENIX_WEBHOOK_SECRET)
  .update(timestamp + '.' + rawBody)
  .digest('hex');
const received = Buffer.from(signature);
const candidate = Buffer.from(expected);

if (!Number.isInteger(Number(timestamp)) || ageSeconds > 300 ||
  received.length !== candidate.length || !timingSafeEqual(received, candidate)) {
  return new Response(null, { status: 400 });
}

const event = JSON.parse(rawBody);
if (await events.has(event.id)) return new Response(null, { status: 204 });

await database.transaction(async () => {
  await events.insert({ id: event.id });
  await applyBookingEvent(event);
});

return new Response(null, { status: 204 });

Політика обробки отримувача

  • Перевірте підпис за незміненим необробленим тілом до розбору JSON. Перевірте формат підпису v1, вікно timestamp та очікувану схему події.
  • Атомарно збережіть X-Fenix-Event-Id до побічних ефектів. X-Fenix-Delivery-Id визначає спробу; Idempotency-Key повторює id події для усунення дублікатів.
  • Повертайте 2xx лише після безпечної обробки події. Redirect відхиляється; невдала доставка отримує щонайбільше п’ять спроб із затримками 1m, 5m, 30m і 2h.
  • Вважайте payload webhook операційними даними. Не передавайте їх у телеметрію браузера й приховуйте в логах, заявках та звітах.

Безпека endpoint

  • Реєструйте лише публічний HTTPS hostname. URL з обліковими даними, fragment, query string або нестандартним портом відхиляються.
  • Платформа визначає й перевіряє DNS перед налаштуванням і кожною доставкою; loopback, приватні, link-local, зарезервовані та змішані адреси блокуються.
  • Одноразовий секрет підпису whsec_ показується власнику лише під час створення або ротації. Зберігайте його в серверному сховищі, ротуйте після витоку й не надсилайте підтримці.
  • Призупиніть endpoint під час інциденту. Повторюйте лише невдалі або пропущені доставки після готовності отримувача усувати дублікати за початковим id події.
Webhooks | Feny для розробників