# `Mailglass.SignatureError`
[🔗](https://github.com/szTheory/mailglass/blob/v0.1.0/lib/mailglass/errors/signature_error.ex#L1)

Raised when webhook signature verification fails.

Webhook signature errors are never retryable — the caller is either
misconfigured (wrong secret) or the request is a forgery. Let the
process crash under supervision and surface a 4xx to the provider.

## Types

The closed atom set is extended per Phase 4 D-21 from the original
four-atom Phase 1 set to the seven-atom webhook-ingest set. The legacy
atoms (`:missing`, `:malformed`, `:mismatch`) remain in the set for
backward compatibility with any code that already raises them; Plan 05
formally hardens the migration with `api_stability.md` documentation
and final message wording.

- `:missing_header` — the provider's signature header is not present on the request (D-21)
- `:malformed_header` — the header is present but cannot be parsed (bad Base64, missing prefix)
- `:bad_credentials` — Postmark Basic Auth user/pass mismatch (`Plug.Crypto.secure_compare/2` returned false)
- `:ip_disallowed` — Postmark IP allowlist mismatch (opt-in; D-04)
- `:bad_signature` — HMAC/ECDSA math returned false; collapses `:tampered_body` per D-21
- `:timestamp_skew` — the signed timestamp is outside the acceptable window
- `:malformed_key` — PEM/DER decode failure at config validate-at-boot time
- `:missing` — (legacy) alias of `:missing_header`; retained until Plan 05 consolidates
- `:malformed` — (legacy) alias of `:malformed_header`; retained until Plan 05 consolidates
- `:mismatch` — (legacy) alias of `:bad_signature`; retained until Plan 05 consolidates

## Per-kind Fields

- `:provider` — the provider atom (`:postmark`, `:sendgrid`, `:mailgun`, …)
  that rejected the request.

See `Mailglass.Error` for the shared contract and `docs/api_stability.md`
for the locked `:type` atom set.

# `t`

```elixir
@type t() :: %Mailglass.SignatureError{
  __exception__: true,
  cause: Exception.t() | nil,
  context: %{required(atom()) =&gt; term()},
  message: String.t(),
  provider: atom() | nil,
  type:
    :missing_header
    | :malformed_header
    | :bad_credentials
    | :ip_disallowed
    | :bad_signature
    | :timestamp_skew
    | :malformed_key
    | :missing
    | :malformed
    | :mismatch
}
```

# `__types__`
*since 0.1.0* 

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

Returns the closed set of valid `:type` atoms. Tested against `docs/api_stability.md`.

# `new`
*since 0.1.0* 

```elixir
@spec new(
  atom(),
  keyword()
) :: t()
```

Build a `Mailglass.SignatureError` struct.

## Options

- `:cause` — an underlying exception to wrap (kept out of JSON output).
- `:context` — a map of non-PII metadata about the request.
- `:provider` — the provider atom that rejected the request.

---

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