# `Accrue.Webhook.WebhookEvent`
[🔗](https://github.com/szTheory/accrue/blob/accrue-v0.3.0/lib/accrue/webhook/webhook_event.ex#L1)

Ecto schema for the `accrue_webhook_events` table.

This is the single-table ledger for all inbound webhook events from
any processor. The `status` column projects Oban's job lifecycle
onto a queryable field for admin UI and retention management (D2-33).

## Status lifecycle

    :received -> :processing -> :succeeded
                             -> :failed -> :dead
    :dead -> :replayed -> :received (replay cycle)

## Raw body storage

`raw_body` is stored as `:binary` (PostgreSQL `bytea`) for byte-exact
forensic replay of signature verification (research Q1). The `Inspect`
protocol is implemented to EXCLUDE `raw_body` from inspect output to
prevent accidental PII logging (T-2-04a).

## Idempotency

The unique index on `(processor, processor_event_id)` ensures each
event is persisted at most once (D2-25). Duplicate POSTs return the
existing row without re-enqueuing.

# `t`

```elixir
@type t() :: %Accrue.Webhook.WebhookEvent{
  __meta__: term(),
  data: term(),
  endpoint: term(),
  id: term(),
  inserted_at: term(),
  livemode: term(),
  processed_at: term(),
  processor: term(),
  processor_event_id: term(),
  raw_body: term(),
  received_at: term(),
  status: term(),
  type: term(),
  updated_at: term()
}
```

# `ingest_changeset`

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

Builds a changeset for the hot-path webhook insert.

Only casts the fields needed at ingestion time. Status defaults to
`:received` via the schema default.

# `status_changeset`

```elixir
@spec status_changeset(
  %Accrue.Webhook.WebhookEvent{
    __meta__: term(),
    data: term(),
    endpoint: term(),
    id: term(),
    inserted_at: term(),
    livemode: term(),
    processed_at: term(),
    processor: term(),
    processor_event_id: term(),
    raw_body: term(),
    received_at: term(),
    status: term(),
    type: term(),
    updated_at: term()
  },
  atom()
) :: Ecto.Changeset.t()
```

Builds a changeset for status transitions.

Used by the Oban dispatch worker to move events through
`:processing` -> `:succeeded` / `:failed` / `:dead` and by the
replay path to reset to `:received`.

# `statuses`

```elixir
@spec statuses() :: [atom()]
```

Returns the list of valid webhook event statuses.

---

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