# `Mailglass.Webhook.WebhookEvent`
[🔗](https://github.com/szTheory/mailglass/blob/v2.7.0/lib/mailglass/webhook/webhook_event.ex#L1)

Ecto schema for the `mailglass_webhook_events` table (V02 migration,
-01). Mutable + prunable — UNLIKE `mailglass_events` which is
append-only via the SQLSTATE 45A01 trigger (CONTEXT  split).

Stores raw webhook payloads from Postmark + SendGrid for:

  * **Idempotency:** UNIQUE `(provider, provider_event_id)` defends
    against replay. The
    `Mailglass.Webhook.Ingest.ingest_multi/3` inserts with
    `on_conflict: :nothing, conflict_target: [:provider, :provider_event_id]`
    — a replay is a no-op SELECT-by-index, not an INSERT.
  * **Audit:** full raw payload available for support / debugging.
  * **GDPR erasure:** targeted `DELETE FROM mailglass_webhook_events
    WHERE raw_payload->>'to' = ?` without touching the append-only
    ledger.

The `:raw_payload` field is marked `redact: true` so `Inspect` output
(test failures, IEx) does NOT leak PII bytes. Mirrors accrue's
`webhook_event.ex:48` convention.

## Status state machine

`:received → :processing → :succeeded | :failed → :dead`. -06
inserts at `:processing` and flips to `:succeeded` at the end of the
Multi; failures (outside -06 scope) will surface the 
DLQ.

# `__statuses__`
*since 0.1.0* 

Closed set of valid `:status` atoms. Cross-checked in api_stability.md.

# `changeset`
*since 0.1.0* 

```elixir
@spec changeset(map()) :: Ecto.Changeset.t()
```

Builds a changeset for inserting a webhook_event row at ingest time.

Caller passes `:provider`, `:provider_event_id`, `:event_type_raw`,
`:tenant_id`, `:raw_payload`. Other fields default sensibly:

  * `:status` defaults to `:processing` (-06 flips to
    `:succeeded` after the Multi commits)
  * `:received_at` defaults to `Mailglass.Clock.utc_now/0`

# `changeset`
*since 2.4.0* 

```elixir
@spec changeset(
  %Mailglass.Webhook.WebhookEvent{
    __meta__: term(),
    event_type_normalized: term(),
    event_type_raw: term(),
    id: term(),
    inserted_at: term(),
    processed_at: term(),
    provider: term(),
    provider_event_id: term(),
    raw_payload: term(),
    raw_signed_body: term(),
    received_at: term(),
    status: term(),
    tenant_id: term(),
    updated_at: term()
  },
  map()
) :: Ecto.Changeset.t()
```

Builds a mutable webhook-event changeset without allowing signed evidence replacement.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
