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

Non-disableable default handler for built-in state reconciliation.

Runs first in the dispatch chain before any user-registered handlers.
Cannot be removed or reordered by configuration.

## Behaviour

Reconciles Stripe webhook families covering subscription, invoice, charge,
refund, and payment method state. Each reducer:

  1. Derives `evt_ts` from the raw event `created` unix timestamp.
  2. Loads the local row by processor id.
  3. **Skip stale:** if `row.last_stripe_event_ts != nil`
     and `evt_ts` is strictly less than it, emit
     `[:accrue, :webhooks, :stale_event]` telemetry and return
     `{:ok, :stale}` **without** calling the processor. Timestamp ties
     (`:eq`) still proceed.
  4. **Refetch canonical:** always call
     `Accrue.Processor.fetch/2` to pull the current object —
     never trust the payload snapshot alone.
  5. Project via the appropriate `*Projection.decompose/1` (or
     schema-specific upsert) and write via the webhook-path
     changeset (`Invoice.force_status_changeset/2` where a legal
     transition bypass is required).
  6. Stamp `last_stripe_event_ts` / `last_stripe_event_id` on the
     row so the next out-of-order event can skip.
  7. Record an `accrue_events` row in the same `Repo.transact/1`.

## Entry points

  * `handle/1` — accepts the raw event map (both string- and
    atom-keyed shapes). Used by `Accrue.Processor.Fake.synthesize_event/3`
    for in-process test dispatch.
  * `handle_event/3` — the `Accrue.Webhook.Handler` behaviour entry
    point invoked by `Accrue.Webhook.DispatchWorker`. Dispatches
    via the existing `%Accrue.Webhook.Event{}` struct (object_id +
    created_at + type) to the shared reducer.

# `handle`

```elixir
@spec handle(map()) :: {:ok, struct() | :stale | :ignored} | {:error, term()}
```

Reduces a raw event map (atom- or string-keyed) through the built-in
reducer chain. Returns `{:ok, row}` on success, `{:ok, :stale}` if
the event is older than `row.last_stripe_event_ts`, or `{:ok, :ignored}`
if the type has no dedicated reducer.

# `handle_event`

---

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