> 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.

# Changelog

## October 19, 2026

## 4.32.4

**`(fix):`** Path parameter values of exactly `.` or `..` now throw an `IllegalArgumentException` before
the request is sent. OkHttp's `addPathSegment` resolves these as dot-segments, so they could
change which endpoint the request was sent to. Values are checked by a new
`core.PathSegments` helper.

## October 16, 2026

## 4.32.3

**`(fix):`** `WebhooksHelper.verifyRequest` now parses `name=value` settings headers when
`webhook-signature.algorithm-header` sets `key-id-parameter`/`algorithm-parameter`
(e.g. Twilio's `X-Twilio-Webhooks-Signature-Settings: key=<id>,algorithm=HMAC_SHA256`),
so the key resolver receives the bare key ID instead of `key=<id>`. Requires IR 67.33.0.

## October 13, 2026

## 4.32.2

**`(fix):`** The generated `WebhooksHelper` now consumes `algorithm-header` from `api.settings.webhook-signature`:
a request-level `verifyRequest` helper reads the configured signature header first (missing or empty
fails early with "could not run: missing signature header"), then the algorithm-selection header
(e.g. `X-Twilio-Webhook-Signature-Settings: <key_id>;HMAC_SHA256`) to pick the HMAC algorithm from
the configured wire values and hand the key ID to an application-supplied secret resolver. When the
header is absent the configured default algorithm and the plain secret are used, so legacy
auth-token flows keep working. The lower-level `verifySignature` is unchanged and still returns
`false` without throwing.

## October 12, 2026

## 4.32.1

**`(fix):`** Unknown JSON keys that match a declared property's wire name case-insensitively (e.g. `VALUE` next to
`value`) are no longer kept in `additionalProperties`, so they are not re-emitted on serialization where a
case-insensitive, last-wins decoder downstream would read them instead of the declared field. Non-colliding
unknown keys are still preserved and round-tripped.

## October 9, 2026

## 4.32.0

**`(feat):`** Support inferred bearer auth with `type: refresh-token`. The token supplier always sends
`grant_type=refresh_token`, and `grantType` is no longer a client builder option. Only the parameters of
the OAuth refresh token grant (`refreshToken`, `scope`, `clientId`, `clientSecret`) plus any required
ones are builder options and sent. Optional parameters of other grants on a shared token endpoint, such as
`code`, `codeVerifier` and `redirectUri`, stay on the token endpoint method only.

**`(feat):`** Inferred auth with `type: refresh-token` rotates the refresh token. When the token response returns a new
`refresh_token`, the supplier uses it for the next refresh and passes it to the optional
`onRefreshTokenRotated(Consumer<String>)` builder option so it can be persisted. With endpoint security, a
provided refresh token selects the refresh token scheme over OAuth client credentials.

## 4.31.0

**`(feat):`** Add the `omit-unused-oauth-setters` config option (default `false`). When enabled, clients with
endpoint-level security no longer generate builder setters for OAuth token-request properties other
than `clientId`/`clientSecret` (for example `code`, `codeVerifier` or `redirectUri` on a token endpoint
shared by several grants). Those setters were stored but never sent by the client-credentials flow.
The token endpoint method itself still accepts every request property.

## 4.30.5

**`(fix):`** With endpoint-level security, the client builder's `token(...)` override for an OAuth
client-credentials scheme now authenticates that scheme with the given access token, taking
precedence over `clientId`/`clientSecret`. Previously the value was stored but never read, so
calls that only accept the OAuth scheme failed with a missing-credentials error.

## 4.30.4

**`(fix):`** `reference.md` is now generated for every output mode, matching the Go and Python generators. It was
previously skipped unless the CLI passed a snippet path (`local-file-system` output without
`snippets: path:` in generators.yml). `README.md` is unchanged and still requires snippets.

## October 8, 2026

## 4.30.3

**`(fix):`** SSE unions discriminated by the `event:` line (`x-fern-discriminator-context: protocol`) now parse
both variant styles: envelope variants (`{event, data: Payload}`) are built from the `data:` JSON,
and payload variants (the `data:` JSON itself) get the `event:` value injected as the discriminant.
The event name no longer has to be repeated inside the `data:` JSON.

## 4.30.2

**`(fix):`** The debug logger now lower-cases header names with `Locale.ROOT` when deciding which headers to
redact, in both the request and response log lines. Before, it used the JVM's default locale, so on a
Turkish or Azerbaijani JVM a header such as `AUTHORIZATION` or `X-API-KEY` lower-cased to a dotless `ı`,
missed the redaction list, and its value was logged in plain text. `LogLevel.fromString` now upper-cases
with `Locale.ROOT` too, so `fromString("info")` no longer throws on those locales.

## 4.30.1

**`(fix):`** Async clients no longer sleep on OkHttp dispatcher threads while waiting to retry. The retry is
scheduled after the backoff delay, so calls that are waiting to retry no longer hold OkHttp's
per-host request slots (5 by default) and delay unrelated calls. Cancelling the returned future
now stops the wait immediately and sends no further attempts.

**`(fix):`** Interrupting a synchronous call while it waits to retry now restores the thread's interrupt
flag and throws `InterruptedIOException`, instead of clearing the flag and throwing a generic
`IOException`.

## October 7, 2026

## 4.30.0

**`(feat):`** XML (TwiML) builders can now carry XML comments. `comment(text)` adds `<!--text-->` inside the element at
its position in the ordered content (interleaved with `addText` segments and child elements), while
`commentBefore(text)` / `commentAfter(text)` render a comment immediately before or after the element
itself (as a sibling in its parent, or around the root element after the XML declaration). Comments in
parsed documents are preserved by `fromXml` and round-trip through `toXml`; `XmlNode.comment(...)`
exposes the same for untyped elements.

## October 6, 2026

## 4.29.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. `omit-fern-headers` still takes precedence and drops
the `User-Agent` too.

## 4.28.0

**`(feat):`** The generated `WebhooksHelper` HMAC verifier now accepts a per-call algorithm override via a `verifySignature(...)` overload taking an `algorithm` argument,
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.

## 4.27.0

**`(feat):`** XML (TwiML) types now keep their content in a single ordered sequence
(`List<XmlNode>` exposed via `getContent()`): typed child methods such as
`say(...)`, `addChild(XmlElement)` and the new `addText(String)` all append
to it, so `toXml()` emits typed children, generic children and text segments
in exactly the order they were added, and `fromXml()` preserves the original
positions. The text property (e.g. `message`) remains the leading text of the
element. New `XmlNode` core class; `XmlReader.leadingText`/`content` and
`XmlWriter.content` helpers.

## 4.26.0

**`(feat):`** SDK variables that declare an environment variable fallback (`env` in `api.yml` or `x-fern-env` on
`x-fern-sdk-variables`) now default to `System.getenv(...)` in the client builder, and `build()`
throws an `IllegalStateException` with a clear message when neither the builder method nor the
environment variable provides a value, instead of rendering `null` into request paths. The check
lives in the generated `setVariables(builder)` hook, so overriding it to supply the value still works.

## 4.25.0

**`(feat):`** Wire tests now cover error responses and every example, not just the first example's happy path.
Each endpoint gets one test per user-specified example. When none of an endpoint's user examples
is an error, the autogenerated error examples are added too. Error tests assert that the call throws
the typed error class (or the base API exception when the status code isn't declared) and check the
status code and error body. Success responses use the endpoint's declared status code instead of
always returning 200, and the test client is built with `maxRetries(0)`.
Set `wire-tests-fallback-to-autogenerated-error-examples: false` to leave out autogenerated error examples.

**`(fix):`** Wire tests now compile when the API has a type named `Test` or `Exception`. The test annotation
and `throws` clause use fully qualified names in that case, so they no longer clash with the imported API type.

## October 5, 2026

## 4.24.2

**`(fix):`** With endpoint-security auth, the client builder now registers OAuth, bearer and basic
auth providers under the auth scheme's configured key (for example `customAuthSchemeName`)
instead of a hardcoded `OAuth`/`Bearer`/`Basic`. Previously, every authenticated call
failed with "No authentication credentials provided" when the scheme key differed.

## 4.24.1

**`(fix):`** XML-encoded (TwiML) types now return their XML representation from
`toString()` instead of JSON, and `toXml()` always prepends the
`<?xml version="1.0" encoding="UTF-8"?>` declaration regardless of
whether the type is a root element. Use `toXml(false)` to omit it.

## 4.24.0

**`(feat):`** Add `addBodyProperty(String, Object)` and `bodyProperties(Map<String, Object>)` request options for sending
request body properties that are not part of the SDK yet. They are merged into JSON and form-urlencoded bodies
using the keys as given, override properties with the same key, and are sent as a JSON body for endpoints
without one. Multipart (file upload) requests are not supported.

## 4.23.3

**`(fix):`** Fix several runtime correctness issues in generated SDKs:
cursor pagers now stop when the next cursor is empty, absent, null, or an empty string;
nested offset and cursor pagination builds an omitted parent options object so the page advances;
pagination compiles with `collapse-optional-nullable: true` when the cursor is `OptionalNullable`;
`4XX`/`5XX` wildcard error responses map to their typed errors, with exact status codes taking precedence;
header auth scheme headers and credential-like global headers (for example `PLAID-CLIENT-ID`) are redacted in debug logs;
cancelling an async `CompletableFuture` cancels the underlying OkHttp call;
the README environment example uses the generated constant name (for example `Environment.PRODUCTION`);
and `reference.md` shows `LocalDate` for date parameters when `use-local-date-for-dates` is enabled.

## October 1, 2026

## 4.23.2

**`(fix):`** Fix `InputStream` upload overloads on multipart endpoints that have
non-file form fields. The overloads now take the generated request
object and serialize every companion multipart field alongside the
streamed file, instead of silently dropping them. The unused
`File`-typed parameter (including `Optional<File>`) is also removed
from these signatures. When the file property is inlined onto the
request object (`inline-file-properties: true`) and companion fields
exist, the stream overloads are no longer generated, since the file
cannot be separated from the request object.

## September 29, 2026

## 4.23.1

**`(chore):`** Bump bundled @fern-api/generator-cli to 0.10.3. When the hosted auto-version analysis of the
full SDK diff fails, generator-cli now retries chunk-by-chunk instead of silently applying a
PATCH bump; any remaining unavailable or incomplete analysis adds a "Version bump not verified"
notice to the SDK PR body and disables automerge.

## September 26, 2026

## 4.22.3

**`(fix):`** Honor `package-prefix` and `package-layout` for `local-file-system` output when the CLI
requests a full project (e.g. `--generate-tests`, `--package`, or self-hosted SDKs).
Previously these were dropped when converting the local-file-system config, so the root
package fell back to `com.<org>.<api>` instead of the configured prefix. Full-project local
output now also writes sources at their full package path (`src/main/java/com/acme/...`)
instead of stripping the prefix from the directory.

## September 25, 2026

## 4.23.0

**`(feat):`** XML-encoded (TwiML) types now carry inline Javadoc on their user-facing API: the class itself gets the
type description, every `Builder` setter overload gets the property description, and child appenders
(`say.break_(...)`, `response.say(...)`) document the child element plus `@param`/`@return`.

## 4.22.2

**`(fix):`** `RetryInterceptor` now applies the client `timeout` to each attempt individually instead of to the
whole retry loop. Previously a `Retry-After` wait as long as the timeout (e.g. `Retry-After: 60`
with the default 60s timeout) cancelled the call during the backoff sleep and surfaced
`IOException: Canceled` instead of retrying or returning the received 429. The call timeout is
paused while waiting for the backoff and restarted for each retry attempt, so a call that retries
may now take up to `timeout * (maxRetries + 1)` plus the backoff waits.

## 4.22.1

**`(fix):`** Closing the root client (or `ClientOptions.close()`) now disconnects any WebSocket clients that are still
connected before the SDK-owned OkHttp dispatcher is shut down, so they stop reconnecting cleanly instead of
failing asynchronously with `InterruptedIOException: executor rejected`. `ClientOptions` exposes `isClosed()`;
WebSocket connect/reconnect attempts made after close, as well as `OkHttpWebSocketFactory.create(...)` when
constructed with a closed-check, fail fast with `IllegalStateException("root client has been closed")`.

## September 24, 2026

## 4.22.0

**`(feat):`** Generate the shared `WebhooksHelper` from the API-wide `api.settings.webhook-signature`
setting in `generators.yml` (IR `sdkConfig.webhookSignatureVerification`). The helper is
emitted even when the API definition models no webhooks; webhook-specific signature
overrides still produce their own named helpers.

**`(fix):`** Fix the generated `ReconnectingWebSocketListener` connection-timeout message, which was missing the
closing parenthesis after the retry attempt number (e.g. `... milliseconds (retry attempt #2`).

## 4.21.2

**`(fix):`** `RetryInterceptor` no longer discards an API response it has already received (e.g. a 429)
when a later retry attempt fails, such as when the call timeout expires mid-retry. The
previous response is buffered and returned instead of surfacing a generic `IOException`.

## September 22, 2026

## 4.21.1

**`(chore):`** Bump bundled @fern-api/generator-cli to 0.10.1. Auto-versioned MAJOR/MINOR bumps no longer
produce a version-only `changelog.md` block when the AI analysis returns an empty changelog
entry; the PR description, version bump reason, or commit message body is used instead.

## 4.21.0

**`(feat):`** Generated root clients (sync and async) now implement `AutoCloseable`. `close()` shuts down
the underlying `OkHttpClient`'s dispatcher executor and evicts its connection pool, but only
when the SDK created that `OkHttpClient` itself — a client supplied via `Builder.httpClient(...)`
is left running, since the caller owns its lifecycle. This lets short-lived applications (e.g.
CLIs, or code that finishes after using WebSockets) release the client's background threads
instead of relying on JVM shutdown.

## September 21, 2026

## 4.20.0

**`(feat):`** Object types with xml encoding metadata (e.g. TwiML defined via OpenAPI `xml` objects) now
implement `XmlSerializable` with `toXml()` and a static `fromXml(String)` parser, backed by new
core `XmlWriter`/`XmlReader` utilities. Builders gain per-child-element methods
(e.g. `Response.builder().say(...)`) and undiscriminated child unions dispatch `fromXml` by
element name. `Builder.fromXml(String)` returns a populated builder, unknown child elements are
preserved as `XmlElement`s (readable via `getAdditionalChildren()`, addable via `addChild(...)`)
and round-tripped by `toXml()`, and very large objects that use a builder-based constructor also
get `fromXml`. Types without xml metadata are unchanged.

## September 15, 2026

## 4.19.3

**`(fix):`** Generated `ReconnectingWebSocketListener` now acknowledges peer-initiated close frames by
overriding `onClosing`, so OkHttp completes the close handshake and `onClosed` (and the
public disconnect lifecycle) fires for server-initiated closes. A no-status close (local
sentinel 1005) is acknowledged with 1000, since 1005 is not a wire-valid close code.
The reconnect decision is exposed as a `protected boolean shouldReconnectAfterClose(WebSocket, int, String)`
hook (default unchanged: `code != 1000`) so resource-specific subclasses can treat a
protocol-established terminal close as final. Adds `send(String, Consumer<WebSocket>)` /
`sendBinary(ByteString, Consumer<WebSocket>)` overloads that report which socket directly
accepted a message (not invoked for queued or dropped messages).

## August 26, 2026

## 4.19.2

**`(fix):`** Respect custom OAuth token headers and prefixes for client credentials authentication.

## August 20, 2026

## 4.19.1

**`(fix):`** Honor an endpoint's `retries: {disabled: true}` configuration (the `x-fern-retries` OpenAPI
extension). A call to such an endpoint tags its request with a max-retries override of zero, so it
bypasses automatic retries regardless of the client-wide `ClientOptions.maxRetries` or a
per-request `RequestOptions.maxRetries`. Endpoints without the configuration are unchanged.

## August 13, 2026

## 4.19.0

**`(fix):`** With `respect-optional-request-body` enabled, a call that leaves out an optional request body now
passes a null body to OkHttp instead of an empty one, so the request carries no body at all. The
methods OkHttp requires a body for (POST, PUT, PATCH) still send an empty body, which is what
endpoints with no request body at all already send.

**`(feat):`** Add a `respect-optional-request-body` option. When enabled, an endpoint whose request body the API
does not require also gets an overload without the body parameter, and calling that overload sends
no body. The body parameter keeps its own type, so `alpha(String id, Body body)` gains a sibling
`alpha(String id)` rather than becoming `alpha(String id, Optional<Body> body)`. Examples that
supply no body render as `client.alpha(id)`. That call also leaves out the `Content-Type` header,
which now only goes out when a body does. The option defaults to false, so existing signatures
and snippets are unchanged.

## 4.18.2

**`(fix):`** Build an empty request body in snippets for an endpoint example that omits a body the wrapped
request requires, instead of leaving the builder's required `body` stage unset.

## 4.18.1

**`(fix):`** Fix the generated OAuth token supplier when the get-token request has required properties
other than the client credentials. The builder calls are now ordered by the request's
required properties, so the staged builder's stages are satisfied in order, and hardcoded
values (such as `grant_type`) are written using the property's type, which means an
enumerated `grant_type` gets the generated enum constant instead of a string literal.

_Showing the 20 most recent of 281 entries. Append `/llms.txt` to the changelog URL for the complete index._