July 22, 2026
2.15.0
(feat): Support webhook body-hash binding in generated signature verification helpers.
When a webhook signature declares a body-hash binding, the helper now recomputes
the encoded hash of the raw request body, extracts the transmitted hash from the
configured query parameter of the notification URL, and timing-safe-compares them
(failing closed) before verifying the outer HMAC over the verbatim notification URL.
(feat): Generate HMAC webhook signature verification helpers from the IR.
(feat): Extend the generated verifySignature webhook helper with Twilio-compatible
verification, mirroring the TypeScript reference:
- Multi-value form params: when
payloadFormat.bodySortis set, the request-body parameter accepts either a raw string or astring|arraymultimap of POST body parameters whose values are a string or a list of strings; keys are sorted, each key’s values are deduped and sorted, andkey . valuepairs are concatenated with no separator before signing. - Runtime body-hash branch: when a
bodyHashBindingis 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
notificationUrlNormalizationis 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-onlynotificationUrlCandidatesmethod (usingparse_url/http_build_query) is added to theWebhookSignaturecore utility. Output is unchanged for webhooks that do not configure these fields, other than the no-throw behavior which applies to all generated helpers.
2.14.1
(fix): Render the selected environment’s URL template(s) when server URL variables
(e.g. region) are provided alongside a named environment. Previously the
first environment’s template was always used, so
new Client(environment: Environments::Staging(), region: 'ie1') resolved
to Production-shaped URLs. A custom environment or explicitly provided
base URL is left untouched.