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

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

Stores raw webhook payloads from Postmark + SendGrid for:

  * **Idempotency:** UNIQUE `(provider, provider_event_id)` defends
    against replay (D-15 + PITFALLS MAIL-03). Plan 04-06's
    `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 (D-15).

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`. Plan 04-06
inserts at `:processing` and flips to `:succeeded` at the end of the
Multi; failures (outside Plan 04-06 scope) will surface the Plan 08
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` (Plan 04-06 flips to
    `:succeeded` after the Multi commits)
  * `:received_at` defaults to `Mailglass.Clock.utc_now/0`

---

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