# `DripDrop.Channels.Helpers`
[🔗](https://github.com/agoodway/dripdrop/blob/v0.1.0/lib/dripdrop/channels/helpers.ex#L1)

Shared helpers for provider implementations.

# `credential`

```elixir
@spec credential(map(), atom() | binary(), term()) :: term()
```

Reads a credential from either an adapter or credential map.

# `drop_nil_values`

```elixir
@spec drop_nil_values(map()) :: map()
```

Removes keys whose values are `nil`.

# `hmac_sha256_verify`

```elixir
@spec hmac_sha256_verify(binary(), iodata(), binary()) :: boolean()
```

Verifies an HMAC-SHA256 hex signature against a key + payload pair.

# `provider_result`

```elixir
@spec provider_result(
  {:ok, %{status: integer(), body: term()}} | {:error, term()},
  atom(),
  (term() -&gt; binary() | nil)
) :: {:ok, map()} | {:error, map()}
```

Normalizes an HTTP provider response into the channel delivery contract.

# `recipient`

```elixir
@spec recipient(term(), map(), binary() | atom()) :: binary() | nil
```

Resolves the recipient for a channel from payload overrides or enrollment data.

# `request_options`

```elixir
@spec request_options(map()) :: keyword()
```

Returns configured `Req` options for channel provider HTTP calls.

Tests and host applications can provide options globally through
`config :dripdrop, :channel_req_options` or per adapter through
`adapter.config["req_options"]`.

# `secure_compare`

```elixir
@spec secure_compare(binary(), binary()) :: boolean()
```

Constant-time comparison of two binaries that also guards size mismatch.

`Plug.Crypto.secure_compare/2` requires equal byte sizes; this wrapper folds
the size check into the comparison so callers can compare a candidate
signature directly without leaking length information.

# `within_skew?`

```elixir
@spec within_skew?(term(), pos_integer(), DateTime.t() | nil) :: boolean()
```

Returns true when `timestamp` is within `max_seconds` of `reference` (default `now`).

Accepts unix timestamps as integer or string and ISO 8601 strings. Used to
reject replayed webhook deliveries.

---

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