> This page is for SDKs, 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.

## 2.28.2

**`(fix):`** List-valued XML (TwiML) attributes accept a single space-separated string in addition to
an array, matching the legacy call style: `new Gather(['input' => 'speech dtmf'])` and
`$response->gather(['input' => 'speech dtmf'])` no longer throw a `TypeError`.

## 2.28.1

**`(fix):`** Enum-typed attributes and text on XML (TwiML) types are open on the wire: `fromXml` keeps a value the enum does
not declare (e.g. a voice added after the SDK was generated) instead of throwing, and it round-trips through
`toXml`. This matches how the same enums already behave in JSON.

## 2.28.0

**`(feat):`** Add opt-in `userAgentOnly` config. When enabled, generated clients send the `User-Agent`
header (including the structured form from `includePlatformHeaders`) but omit the
`X-Fern-Language`, `X-Fern-SDK-Name`, and `X-Fern-SDK-Version` headers. Disabled by default,
so existing generated output is unchanged. `omitFernHeaders` still takes precedence and drops
the `User-Agent` too.

## 2.27.0

**`(feat):`** The generated `WebhooksHelper` HMAC verifier now accepts a per-call algorithm override via an optional `algorithm` parameter on `verifySignature`,
one of `sha1`, `sha256`, `sha384` or `sha512`. When omitted, the algorithm configured in
`webhook-signature` is used, so existing callers are unchanged. This lets one endpoint verify both
legacy HMAC-SHA1 (auth-token) and HMAC-SHA256 (shared-key) signed webhooks.
The verifier also logs a warning distinguishing an early failure (missing signature header) from a
failed verification (signature mismatch); it still returns `false` and never throws.

## 2.26.0

**`(feat):`** XML (TwiML) types keep text segments, typed child elements and raw `XmlElement` children in a
single ordered content list, so `toXml()` emits them in the order they were added
(`$response->say(['message' => 'a']); $response->addChild(new XmlElement('Custom')); $response->say(['message' => 'b']);`
yields `<Say>a</Say><Custom/><Say>b</Say>`) and `fromXml()` preserves document order, including
the position of unknown elements. Adds `addText(string)` to XML types and `XmlElement` for mixed
content such as `<Say>Hi <break strength="weak"/> world</Say>`. Typed child properties and
additional children remain available and are reconciled into the content order on serialization.

## 2.25.1

**`(fix):`** XML-encoded (TwiML) types now include the `<?xml version="1.0" encoding="UTF-8"?>`
declaration by default when serialized to XML; pass the declaration flag as `false`
to omit it. Nested child elements and raw `XmlElement`s are still written without it.

## 2.25.0

**`(feat):`** Add support for SDK variables (`x-fern-sdk-variables` / `variables` in `api.yml`). Each variable
becomes an optional, named constructor parameter on the root client (also settable through the
`options` array and per request). Path parameters bound to a variable are removed from endpoint
method signatures and request classes and resolved from the client instead. String variables
that declare an environment variable fall back to `getenv()` when no value is passed, and a
clear `InvalidArgumentException` is thrown when a bound variable is still unset at call time.