> For clean Markdown content of this page, append .md to this URL. For the complete documentation index, see https://buildwithfern.com/learn/llms.txt.

## 4.15.1

**`(fix):`** Fix `ConsoleLogger` dropping DEBUG-level log messages. The `ConsoleHandler` used by the
default logger keeps java.util.logging's default `INFO` handler level, so `FINE` records
(SDK debug logs, including HTTP request/response logging) were silently discarded even
when `LogConfig` was configured with `LogLevel.DEBUG` and `silent(false)`. The handler
level is now set to `ALL` so the configured `LogLevel` controls filtering.

## 4.15.0

**`(feat):`** Add webhook body-hash binding support. When a webhook's HMAC signature verification
declares a `bodyHashBinding` in the IR, the generated `verifySignature` helper now
recomputes the encoded hash of the raw request body using the binding's own
algorithm/encoding, extracts the configured query parameter from the notification URL,
and timing-safe-compares them (failing closed) before performing the existing HMAC
verification over the verbatim notification URL. A stdlib-only `WebhookBodyHash` core
utility (unkeyed digest plus read-only query-parameter extraction) is emitted alongside
the existing signature utility. Output is unchanged when no binding is present.

**`(feat):`** Add webhook signature verification support. When a webhook declares HMAC signature
verification in the IR, the generated SDK now emits a `WebhooksHelper` with a static
`verifySignature` method and a stdlib-only core utility for HMAC computation and
constant-time comparison.

**`(feat):`** Extend the generated `verifySignature` webhook helper with Twilio-compatible
verification, mirroring the TypeScript reference:

* Multi-value form params: when `payloadFormat.bodySort` is set, a `Map<String, ?>`
  overload accepts POST body parameters whose values are a `String` or a
  `Collection<String>`; keys are sorted, each key's values are deduped and sorted, and
  `key + value` pairs are concatenated with no separator before signing.
* Runtime body-hash branch: when a `bodyHashBinding` is configured, the configured
  query parameter is read from the notification URL at runtime. When present (JSON) the
  raw body is hashed and constant-time compared and the signature is checked over the
  URL only; when absent (classic form) the signature is checked over the URL + params
  with no body-hash check.
* No-throw: the verifier is a pure boolean. Every throw on the verification path (null
  or empty inputs, a missing/malformed timestamp) now returns `false`.
* URL any-match normalization: when `notificationUrlNormalization` is configured, the
  signature is verified against several normalized notification-URL candidates
  (standard-port/no-port variants and legacy query re-encoding), accepting on the first
  constant-time match. A stdlib-only `notificationUrlCandidates` method is added to the
  `WebhookSignature` core utility.
  Output is unchanged for webhooks that do not configure these fields, other than the
  no-throw behavior which applies to all generated helpers.