> This page is for SDK, version Legacy.
> For other versions, use one of these documentation indexes:
> - Current (default): https://buildwithfern.com/learn/sdks/current/llms.txt
> - Legacy: https://buildwithfern.com/learn/sdks/legacy/llms.txt

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

## 5.21.0

**`(feat):`** Add webhook body-hash binding support to `verify_signature`. When a webhook's HMAC
signature declares a `bodyHashBinding` in the IR, the generated helper first recomputes
the raw request body's hash (using the binding's own algorithm/encoding), extracts the
configured query parameter from the notification URL, and timing-safe-compares them
(failing closed on a missing or mismatched hash) before performing the existing HMAC
verification over the verbatim notification URL. Adds stdlib-only `compute_hash` (unkeyed
digest) and read-only `get_webhook_query_parameter` core utilities. Output is unchanged
when no body-hash 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
`verify_signature` method that validates the signature (and optional timestamp) using a
new stdlib-only core utility (`hmac`/`hashlib`/`base64` with constant-time comparison).

**`(feat):`** Extend `verify_signature` with Twilio-compatible webhook verification. The generated
helper now (1) accepts either a raw string or a multi-value form map for `request_body`
when the IR sets `payloadFormat.bodySort`, sorting and deduping keys and per-key values
before signing; (2) branches at runtime on a `bodyHashBinding`: a JSON request (body-hash
query parameter present) recomputes and timing-safe-compares the raw-body hash and signs
the notification URL only, while a classic form request signs the URL plus the sorted
params with no body-hash check; (3) verifies against several normalized notification-URL
forms when `notificationUrlNormalization` is set, succeeding on the first constant-time
match; and (4) is a pure boolean that fails closed with `False` on invalid inputs
(missing parameters, malformed timestamps, unparseable URLs) rather than raising. Adds a
stdlib-only `notification_url_candidates` core utility (port and legacy-query-encoding
variants via `urllib.parse`). Output is unchanged for webhooks that do not configure these
fields, aside from the no-throw behavior on the verification path.