Skip to content

Event schemas moved

The v1.5.0 integration event JSON Schemas now live at api/schemas_v1/events/.

They were relocated from this directory in #137 so that the api container's Docker image (which builds from the ./api/ context) actually carries them. The schemas are a runtime API contract loaded at Flask boot by api/services/events_schema_registry.py, not human-facing documentation, so they belong with the code that consumes them.

Each subdirectory is named after an event type (receipt.completed, adjustment.applied, etc.) and contains one JSON Schema file per version (1.json, future 2.json, ...). See the API reference for the event catalog and the wire format.

Consumer contract: dedupe on event_id, not source_txn_id (v1.5.1 V-211 #155)

Every event envelope carries both event_id (server-side BIGSERIAL, monotonic, not client-settable) and source_txn_id (UUID, client-settable via the X-Request-ID request header that triggered the emit). Only event_id is safe as a dedupe key.

source_txn_id is a Sentry-internal idempotency key: its job is to collapse retries of the same HTTP request into one integration_events row via the ON CONFLICT (aggregate_type, aggregate_id, event_type, source_txn_id) DO NOTHING constraint. It is exposed on the wire for distributed-tracing convenience, but any authenticated caller can set it to an arbitrary UUID by sending X-Request-ID: <uuid>. A consumer that dedupes on source_txn_id alone is trusting a value an attacker inside the Sentry deployment can steer; one legitimate caller with a deterministic X-Request-ID pattern is enough to poison downstream dedupe for future events on the same aggregate.

Correct shape: consumers process every event whose event_id is strictly greater than the last event_id successfully applied. Use source_txn_id only for correlation / tracing, never for "have I seen this before" checks.

Per Sentry's polling contract, event_id is server-generated BIGSERIAL and the outbox's deferred visible_at trigger keeps readers ordering on (visible_at, event_id) in commit order even when BIGSERIAL allocates event_ids out of commit order. Dedupe on event_id is therefore sound against both replay and out-of-order emission.