Перейти к основному содержимому

Bounded Webhook Payload Examples For External Projections — Примеры внешних bounded webhook payloads

Версия: 1.0
Дата: 24.04.2026
Статус: Готов к обсуждению

Назначение документа

Этот документ фиксирует первые bounded example payloads для внешних async projections платформы.

Его задача — показать:

  • как внутренние high-value events должны проецироваться во внешние webhook contracts;
  • какие поля допустимы во внешнем payload, а какие должны оставаться внутренними;
  • как удерживаются tenant, partner, correlation, delivery, retry и reconciliation semantics на внешнем surface;
  • как bounded projection отличается от richer internal domain event.

Документ не является финальным webhook schema package. Он является example-layer для внешнего async surface после catalog и compatibility/boundary policy.

Опорные документы

Почему Этот Документ Нужен Отдельно

После появления:

  • внутреннего example-layer;
  • webhook boundary policy;
  • external projection catalog;

уже недостаточно знать только, какие projections разрешены теоретически.

Нужен следующий практический слой, который показывает:

  • как именно должна выглядеть bounded внешняя форма;
  • где проходит граница между полезным внешним контекстом и утечкой внутренней кухни;
  • как делать webhook payload usable, не превращая его во второй internal event bus.

Без этого команда будет либо слишком копировать внутренние payload-ы наружу, либо делать слишком бедные уведомления без operational value.

Главный Принцип

Внешний webhook payload должен быть:

  • partner-comprehensible;
  • contract-stable;
  • bounded;
  • sufficient for external workflow continuation;
  • explicit about pull reconciliation where full truth is not embedded.

Общая Внешняя Envelope Discipline

Для примеров ниже используется bounded external envelope:

  • notification_name
  • notification_version
  • notification_id
  • occurred_at
  • delivery_scope
  • partner_id
  • tenant_id
  • surface_class
  • correlation_id
  • idempotency_key
  • pull_reconciliation_ref
  • payload

Во внешний envelope намеренно не выносятся:

  • raw internal schema_family
  • internal delivery_class
  • operator-only causation chains
  • raw internal producer/runtime names

Example 1. quote-invalidated

Surface Fit

  • agency working surface
  • partner API surface
  • white-label surface

Example Payload

{
"notification_name": "quote-invalidated",
"notification_version": "1.0",
"notification_id": "wh_qinv_01J9X2A7B8C9D0E1F2G3H4J5",
"occurred_at": "2026-04-24T18:14:20Z",
"delivery_scope": "partner-webhook",
"partner_id": "partner_standard_travelhub",
"tenant_id": "tenant_travelhub_eu",
"surface_class": "partner-api",
"correlation_id": "corr_quote_01J9X28A7S6D5F4G3H2J1K0L",
"idempotency_key": "quote-invalidated:quote_01J9X27AA11BB22CC33DD44EE:v1",
"pull_reconciliation_ref": "quote_01J9X27AA11BB22CC33DD44EE",
"payload": {
"quote_id": "quote_01J9X27AA11BB22CC33DD44EE",
"quote_state": "invalidated",
"reason_class": "upstream-offer-change",
"action_required": "refresh-before-booking",
"customer_visible_effect": "quoted-price-no-longer-valid"
}
}

Что Здесь Важно

  • нет внутренних repricing internals;
  • есть чёткий bounded reason_class;
  • webhook не притворяется полным price snapshot;
  • consumer понимает, что нужно подтянуть fresh quote state через pull.

Example 2. booking-confirmed

Surface Fit

  • agency working surface
  • partner API surface
  • white-label surface
  • selected customer-facing self-service surface

Example Payload

{
"notification_name": "booking-confirmed",
"notification_version": "1.0",
"notification_id": "wh_bconf_01J9X2M4N5B6V7C8X9Z0A1S2",
"occurred_at": "2026-04-24T18:20:42Z",
"delivery_scope": "partner-webhook",
"partner_id": "partner_standard_travelhub",
"tenant_id": "tenant_travelhub_eu",
"surface_class": "partner-api",
"correlation_id": "corr_booking_01J9X2K3L4M5N6B7V8C9X0Z1",
"idempotency_key": "booking-confirmed:booking_01J9X2J1H2G3F4D5S6A7P8O9:v1",
"pull_reconciliation_ref": "booking_01J9X2J1H2G3F4D5S6A7P8O9",
"payload": {
"booking_id": "booking_01J9X2J1H2G3F4D5S6A7P8O9",
"booking_state": "confirmed",
"external_reference": "BK-2026-000184",
"supplier_reference_available": true,
"follow_up_state": "none",
"customer_visible_effect": "booking-confirmed"
}
}

Что Здесь Важно

  • есть bounded external reference;
  • supplier reference не утаскивает весь внутренний transactional context;
  • payload пригоден и для machine consumer, и для human workflow refresh.

Example 3. booking-requires-action

Surface Fit

  • agency working surface
  • partner API surface
  • white-label surface

Example Payload

{
"notification_name": "booking-requires-action",
"notification_version": "1.0",
"notification_id": "wh_bact_01J9X31Q2W3E4R5T6Y7U8I9O",
"occurred_at": "2026-04-24T18:27:09Z",
"delivery_scope": "partner-webhook",
"partner_id": "partner_whitelabel_orbit",
"tenant_id": "tenant_orbit_whitelabel",
"surface_class": "white-label",
"correlation_id": "corr_booking_01J9X2K3L4M5N6B7V8C9X0Z1",
"idempotency_key": "booking-requires-action:booking_01J9X2J1H2G3F4D5S6A7P8O9:v1",
"pull_reconciliation_ref": "booking_01J9X2J1H2G3F4D5S6A7P8O9",
"payload": {
"booking_id": "booking_01J9X2J1H2G3F4D5S6A7P8O9",
"booking_state": "requires_action",
"action_class": "partner-follow-up-needed",
"severity_class": "high",
"customer_visible_effect": "booking-not-fully-resolved"
}
}

Что Здесь Важно

  • не раскрывается внутренний recovery path;
  • но внешний consumer понимает urgency и bounded action class;
  • pull reconciliation ref даёт путь к более полной read model.

Example 4. supplier-disruption-affecting-booking

Surface Fit

  • agency working surface
  • partner API surface
  • white-label surface
  • selected customer-facing self-service surface

Example Payload

{
"notification_name": "supplier-disruption-affecting-booking",
"notification_version": "1.0",
"notification_id": "wh_disrupt_01J9X3C4V5B6N7M8A9S0D1F2",
"occurred_at": "2026-04-24T18:36:55Z",
"delivery_scope": "partner-webhook",
"partner_id": "partner_standard_travelhub",
"tenant_id": "tenant_travelhub_eu",
"surface_class": "partner-api",
"correlation_id": "corr_postbooking_01J9X3A1S2D3F4G5H6J7K8L9",
"idempotency_key": "supplier-disruption-affecting-booking:booking_01J9X2J1H2G3F4D5S6A7P8O9:v1",
"pull_reconciliation_ref": "postbooking_case_01J9X39P8O7I6U5Y4T3R2E1W",
"payload": {
"booking_id": "booking_01J9X2J1H2G3F4D5S6A7P8O9",
"impact_class": "supplier-service-disruption",
"action_required": "review-updated-booking-options",
"customer_visible_effect": "confirmed-booking-needs-follow-up",
"service_case_state": "open"
}
}

Что Здесь Важно

  • внешний payload не показывает внутренний SLA или operator routing;
  • но даёт партнёру достаточно сигнала для service workflow;
  • case truth остаётся доступной через bounded pull contract.

Example 5. quota-exhausted

Surface Fit

  • partner API surface
  • white-label operator surface

Example Payload

{
"notification_name": "quota-exhausted",
"notification_version": "1.0",
"notification_id": "wh_quota_01J9X3N5M6B7V8C9X0Z1A2S3",
"occurred_at": "2026-04-24T18:42:11Z",
"delivery_scope": "partner-webhook",
"partner_id": "partner_standard_travelhub",
"tenant_id": "tenant_travelhub_eu",
"surface_class": "partner-api",
"correlation_id": "corr_usage_01J9X3M4N5B6V7C8X9Z0A1S2",
"idempotency_key": "quota-exhausted:partner_standard_travelhub:search-requests:v1",
"pull_reconciliation_ref": "usage_profile_partner_standard_travelhub",
"payload": {
"governance_state": "quota_exhausted",
"affected_capability": "search-requests",
"enforcement_effect": "requests-may-be-rejected",
"action_required": "contact-platform-or-wait-for-reset",
"customer_visible_effect": "integration-capacity-limited"
}
}

Что Здесь Важно

  • payload не раскрывает внутреннюю enforcement matrix;
  • но честно отражает business effect для партнёра;
  • bounded capability naming и effect semantics пригодны для стабильного контракта.

Example 6. proposal-published

Surface Fit

  • agency working surface
  • white-label surface
  • customer-facing proposal surface

Example Payload

{
"notification_name": "proposal-published",
"notification_version": "1.0",
"notification_id": "wh_prop_01J9X3Z7X8C9V0B1N2M3A4S5",
"occurred_at": "2026-04-24T18:48:33Z",
"delivery_scope": "proposal-webhook",
"partner_id": "partner_whitelabel_orbit",
"tenant_id": "tenant_orbit_whitelabel",
"surface_class": "white-label",
"correlation_id": "corr_proposal_01J9X3Y6T5R4E3W2Q1A0S9D8",
"idempotency_key": "proposal-published:proposal_01J9X3X5C4V3B2N1M0L9K8J7:v1",
"pull_reconciliation_ref": "proposal_01J9X3X5C4V3B2N1M0L9K8J7",
"payload": {
"proposal_id": "proposal_01J9X3X5C4V3B2N1M0L9K8J7",
"proposal_state": "published",
"publication_scope": "customer-viewable",
"current_version_label": "v3",
"customer_visible_effect": "proposal-ready-to-view"
}
}

Что Здесь Важно

  • proposal publication не смешан с internal offer publication;
  • payload остаётся presentation-safe;
  • customer-facing effect явно отделён от internal composition lifecycle.

Что Не Надо Делать По Образцу Этих Примеров

Пока не нужно:

  • делать внешние webhook payload-ы snapshot-heavy без необходимости;
  • копировать внутренние schema_family, producer, delivery_class и operator-only codes;
  • пытаться через webhook полностью заменить bounded pull/read contracts;
  • смешивать partner-facing и end-customer-facing payload semantics в одном contract family.

Что Должно Появиться Следом

Следующий практический слой после этого документа:

  • partner-class-specific subscription policy draft;
  • webhook delivery operations and support playbook;
  • first field catalogs for external webhook contracts;
  • future formal external webhook schema package.

Этот документ делает внешний async surface заметно ближе к реальному implementation-ready contract layer.

Уточнение под Фазы 4–6 (28.04.2026)

Bounded webhook payload examples для external projections — использовать каноничные структуры из reference-документов фаз 4–6:

Каноничный сводный каталог имён — initial-event-taxonomy.md.

Уточнение выполнено через no-destruction.