---
id: DOM-PFM-INT-004
title: Integration Event
realises: CON-PFM-INT-004
product_area: platform
module: integrations
revision: 1
status: draft
design_intent: proposed
implementation_evidence: observed
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
  macroservice-libraries: 54536a441935c6e09fdb7f96f0bec71c52ba4e03
owned_by: SVC-PFM-INT-integrations
lifecycle:
  - STATE-PFM-INT-005
  - STATE-PFM-INT-009
  - STATE-PFM-INT-010
  - STATE-PFM-INT-011
  - STATE-PFM-INT-012
custom_fields: none
identity: >-
  Endpoints and message, event and delivery records use generated identifiers. Endpoint address tokens
  identify ingress. Deduplication keys combine the endpoint with provider identity or body digest, or the
  subscription with the source change.
attributes:
  - name: webhook endpoint
    kind: document
    required: true
    computed: false
    notes: >-
      Endpoints retain account and kind, token address, registration method, provider reference, secret
      pointers and active, rotating or disabled status.
  - name: received message
    kind: document
    required: true
    computed: false
    notes: >-
      Messages retain raw body and selected-header references, digest, verification and processing results,
      attempts, generated events and replay origin.
  - name: deduplication keys
    kind: collection
    required: false
    computed: true
    notes: Endpoint keys recognize provider event identifiers indefinitely and body digests for one day.
  - name: integration event
    kind: document
    required: true
    computed: false
    notes: 'Typed events retain source, subject, matched Rhythm context, data and routing outcome.'
  - name: consumer registration
    kind: document
    required: true
    computed: false
    notes: >-
      Global declarations identify the application principal, consumer function and event types or prefixes
      handled.
  - name: subscription
    kind: document
    required: true
    computed: false
    notes: >-
      Subscriptions retain the installation, optional account, event interest, filter, push or pull mode and
      pause status.
  - name: delivery
    kind: document
    required: true
    computed: false
    notes: >-
      Deliveries retain projected payloads, attempts, errors, acknowledgement and pending, delivered,
      retrying, failed, dead or filtered status.
  - name: queued work
    kind: collection
    required: false
    computed: true
    notes: 'Dispatch records carry webhook, routing or delivery work until their queues accept it.'
relationships:
  - to: DOM-PFM-INT-002
    cardinality: An endpoint and each received message identify one connection.
    ownership: Disconnection disables endpoints while received-message history remains.
    cross_service: false
  - to: DOM-PFM-INT-001
    cardinality: Each subscription names one installation and can select an individual account.
    ownership: Uninstallation removes subscriptions while delivery history remains visible.
    cross_service: false
  - to: DOM-PFM-INT-003
    cardinality: An asynchronous or unanswered call creates its applicable completion event.
    ownership: Settlement writes that event and routing limits it to the initiating application.
    cross_service: false
invariants:
  - id: INV-DOM-PFM-INT-004-01
    statement: >-
      Webhook ingress saves the raw body and selected headers before recording its message and dispatch work
      or acknowledging receipt.
    enforced_at:
      - service
    provenance: test
    source: >-
      services-platform:modules/integrations/tests/integration/services/webhooks/ingress.integration.spec.js#stores
      the body and headers, then records the event pending and queued with its digest and a queue row
  - id: INV-DOM-PFM-INT-004-02
    statement: >-
      Processing deduplicates an already processed provider event identifier without expiry and a body digest
      for one day; explicit replay bypasses those checks.
    enforced_at:
      - service
      - database
    provenance: test
    source: >-
      services-platform:modules/integrations/tests/integration/services/webhooks/webhook-worker.integration.spec.js#ignores
      a second request with the provider event id of one already processed, pointing at the first
  - id: INV-DOM-PFM-INT-004-03
    statement: The old and new signing secrets remain usable during the one-day rotation window.
    enforced_at:
      - service
    provenance: test
    source: >-
      services-platform:modules/integrations/tests/integration/services/webhooks/webhook-worker.integration.spec.js#verifies
      with the previous secret too while the endpoint rotates
  - id: INV-DOM-PFM-INT-004-04
    statement: >-
      The router sends at most ten events per consumer invocation and can redeliver handled events; each
      consumer must recognize event identifiers.
    enforced_at:
      - service
    provenance: observed
    source: 'services-platform:modules/integrations/services/events/event-router.ts:routeIntegrationEvents'
  - id: INV-DOM-PFM-INT-004-05
    statement: Completion routing selects the consumer belonging to the application that initiated the execution.
    enforced_at:
      - service
    provenance: test
    source: >-
      services-platform:modules/integrations/tests/e2e-adapters/events-dummy.adapters.spec.js#reaches the
      consumer of the application that invoked it, carrying the response
  - id: INV-DOM-PFM-INT-004-06
    statement: >-
      Creating a subscription requires an enabled installation and an event type both declared by its current
      release and accepted by the customer.
    enforced_at:
      - api
      - service
    provenance: test
    source: >-
      services-platform:modules/integrations/tests/integration/services/subscriptions/subscriptions.integration.spec.js#refuses
      a subscription to a type the installation has not accepted, naming the type, and writes nothing
  - id: INV-DOM-PFM-INT-004-07
    statement: >-
      A subscription and change share one delivery identity, and its payload contains only the event
      projection’s allowed fields.
    enforced_at:
      - service
      - database
    provenance: test
    source: >-
      services-platform:modules/integrations/tests/integration/services/subscriptions/subscriptions.integration.spec.js#turns
      a CRM change event into a queued delivery of the catalog projection, never the row
  - id: INV-DOM-PFM-INT-004-08
    statement: Fifty successive dead deliveries pause an active subscription and request one administrator notice.
    enforced_at:
      - service
    provenance: test
    source: >-
      services-platform:modules/integrations/tests/integration/services/subscriptions/subscriptions.integration.spec.js#pauses
      a subscription after fifty dead deliveries in a row and tells its administrators once
  - id: INV-DOM-PFM-INT-004-09
    statement: >-
      Removing an event type from accepted access pauses active subscriptions atomically; restoring access
      does not resume them.
    enforced_at:
      - service
    provenance: test
    source: >-
      services-platform:modules/integrations/tests/integration/services/subscriptions/subscription-consent.integration.spec.js#pauses
      the active subscription of the type left out
readable_by:
  - SVC-PFM-INT-integrations
physical:
  - platform.integration_webhook_endpoints
  - platform.integration_webhook_events
  - platform.integration_webhook_event_keys
  - platform.integration_events
  - platform.integration_event_consumers
  - platform.integration_subscriptions
  - platform.integration_deliveries
  - platform.integration_delivery_keys
  - platform.integration_work_dispatches
evidence:
  - >-
    services-platform at ad3f6a65: modules/integrations/db/integration-webhook-*.table.ts,
    integration-events.table.ts, integration-event-consumers.table.ts, integration-subscriptions.table.ts,
    integration-deliveries.table.ts, integration-work-dispatches.table.ts; services/webhooks/*;
    services/events/*; services/subscriptions/*; services/work/*
  - >-
    services-platform at ad3f6a65: docs/integrations/README.md (Webhooks; Integration events; Subscriptions
    and deliveries); docs/milestones/INTG-M3-webhooks-events-deliveries.md (status Proposed)
  - 'macroservice-libraries at 54536a44: packages/integration-contracts/src/events.ts, domain-events.ts'
---

# Integration Event

## What It Models

Integration events describe information crossing the provider boundary. An incoming message preserves what arrived, an interpreted event carries meaning to applications, and an outgoing delivery represents one subscription’s projected copy of a Rhythm change. These records have separate processing outcomes even when they concern the same business operation.

## Identity and Attributes

Endpoints and message, event and delivery records use generated identifiers. Endpoint address tokens identify ingress. Deduplication keys combine the endpoint with provider identity or body digest, or the subscription with the source change.

Endpoints retain account and kind, token address, registration method, provider reference, secret pointers and active, rotating or disabled status. Messages retain raw body and selected-header references, digest, verification and processing results, attempts, generated events and replay origin. Endpoint keys recognize provider event identifiers indefinitely and body digests for one day. Typed events retain source, subject, matched Rhythm context, data and routing outcome. Global declarations identify the application principal, consumer function and event types or prefixes handled. Subscriptions retain the installation, optional account, event interest, filter, push or pull mode and pause status. Deliveries retain projected payloads, attempts, errors, acknowledgement and pending, delivered, retrying, failed, dead or filtered status. Dispatch records carry webhook, routing or delivery work until their queues accept it.

## Relationships

An endpoint and each received message identify one connection.. Disconnection disables endpoints while received-message history remains.. Each subscription names one installation and can select an individual account.. Uninstallation removes subscriptions while delivery history remains visible.. An asynchronous or unanswered call creates its applicable completion event.. Settlement writes that event and routing limits it to the initiating application..

## Invariants

Webhook ingress saves the raw body and selected headers before recording its message and dispatch work or acknowledging receipt. Processing deduplicates an already processed provider event identifier without expiry and a body digest for one day; explicit replay bypasses those checks. The old and new signing secrets remain usable during the one-day rotation window. The router sends at most ten events per consumer invocation and can redeliver handled events; each consumer must recognize event identifiers. Completion routing selects the consumer belonging to the application that initiated the execution. Creating a subscription requires an enabled installation and an event type both declared by its current release and accepted by the customer. A subscription and change share one delivery identity, and its payload contains only the event projection’s allowed fields. Fifty successive dead deliveries pause an active subscription and request one administrator notice. Removing an event type from accepted access pauses active subscriptions atomically; restoring access does not resume them.

## How It Is Stored and Shared

The integrations service owns endpoint, message, routing and subscription records. Raw notification bodies and selected headers are stored separately from database rows. Consumer declarations are global; message and delivery records belong to a workspace. The service exposes projected information rather than unrestricted business-record reads, and enables no custom fields.

## Open Design Questions

The event milestone still needs Product’s acceptance decisions. Consumer retries require explicit deduplication obligations. Pull delivery exists separately from the unfinished synchronization-profile pages, and data-grant routes remain unimplemented.
