Changelog
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.
4.14.6
(fix): Fixed an issue where the client builder rendered the first environment’s URL
template instead of the selected environment’s template when both a named
environment and server URL variables (e.g. region) were provided. The
builder now resolves the template(s) from the selected environment, falls
back to the first templated environment when no environment is selected, and
no longer overrides a custom environment or explicitly provided base URL.
4.14.5
(fix): Honor includePlatformHeaders when generating to local file system output.
Previously the flag was only read for GitHub/publish output, so locally
generated SDKs always emitted the static {package}/{version} User-Agent
instead of the structured {package}/{version} (os; arch) Java/{version} form.
4.14.4
(fix): Make the smart-casing digit/word boundary behavior opt-in via the new
smart-casing-digit-word-boundary option in generators.yml. By default, snake_case
names keep a digit run fused to the following word (conversations_v2configuration),
restoring pre-4.13.4 output. When enabled, the word boundary after the digit run is
preserved (conversations_v2_configuration).
4.14.3
(fix): Endpoints without a request wrapper (no request object, or a request that is
just a body) now send service- and endpoint-level headers whose types are
literals (e.g. Accept-Encoding: literal<"gzip">). Previously these headers
were silently dropped because there was no request object to carry them.
4.14.2
(fix): Fix a NullPointerException when constructing an OAuth-only client under multi-scheme
(any) auth combining OAuth client-credentials with an API-key header. Building via
withCredentials(...) (no apiKey(...)) previously baked a null API-key header into
ClientOptions, which crashed okhttp Headers.of on the first HTTP call (the token
fetch). The generated setAuthentication now guards the API-key header add on a non-null
value, and ClientOptions.Builder.addHeader(String, String) defensively skips null values.
Supplying both credentials and an API key still sends both the Authorization: Bearer
and the API-key header, and an API-key-only client still validates the key at build time.
4.14.1
(fix): OAuth client credentials token requests now send grant_type: "client_credentials"
when the token endpoint declares a non-literal grant_type request property. The
property is synthesized in the token request and is no longer surfaced as a
builder option.
4.14.0
(feat): Idempotency-key auto-generation is now driven by the IR (SdkConfig.idempotencyKeyGeneration)
instead of a per-generator config flag. When enabled, the SDK adds the configured idempotency
header on the configured HTTP methods unless the caller already supplied one. The header name
and eligible methods come from the IR, and generated output is unchanged when the feature is off.
4.13.4
(fix): Fix smart-casing snake_case names dropping the word boundary after a number.
Names like ConversationsV2Configuration now produce the snake_case
conversations_v2_configuration instead of conversations_v2configuration,
matching the camelCase and pascalCase variants.
4.13.3
(chore): Upgrade the Java SDK generator to consume IR v67. The generated SDK output is unchanged.
4.13.2
(fix): Fix the OAuth OAuthTokenSupplier generator to derive each get-token request
property’s Java type from its IR TypeReference (via PoetTypeNameMapper)
instead of hardcoding String. Previously a non-string token-request property
(e.g. permissions: Optional<List<String>>) generated a String field and a
.permissions(String) builder call that did not match the request builder’s
typed setter, breaking compilation of the entire SDK. The generated custom
property fields, constructor parameters, client-builder setters, and request
builder calls now use the property’s real type.
4.13.1
(fix): Make the generated User-Agent comply with the RFC 7230 token grammar. The
Maven coordinate in the product token now uses a dot instead of a colon, since
a colon is not a valid token character (e.g. com.fern:imdb/0.0.1 becomes
com.fern.imdb/0.0.1); this applies to both the plain header value and the
structured value emitted when includePlatformHeaders is enabled. For the
structured value, the architecture label is also normalized so the 64-bit x86
aliases (x64, amd64, x86_64) all report as the canonical x86_64.
4.13.0
(feat): Add opt-in support for a structured User-Agent header on generated SDK clients,
of the form {sdkName}/{sdkVersion} ({os}; {arch}) {runtime}/{runtimeVersion}
(e.g. com.fern:sdk/0.0.1 (linux; amd64) Java/17.0.13). The os
(System.getProperty("os.name"), lowercased), arch (System.getProperty("os.arch")),
and runtime version (System.getProperty("java.version")) are resolved at runtime;
any segment that cannot be determined is omitted rather than emitted as null.
This is gated behind a new includePlatformHeaders config option and is disabled by
default, so existing generated output is unchanged. When enabled, the header is still
subject to omit-fern-headers.
4.12.1
(fix): Decompress gzip and deflate encoded response bodies via a new
ResponseDecompressionInterceptor added to the generated OkHttpClient.
OkHttp only performs transparent gzip decompression when it adds the
Accept-Encoding header itself, so responses to requests with a
spec-defined Accept-Encoding: gzip header were previously returned as
raw gzip bytes.
4.12.0
(feat): Add client builder options to customize the retry backoff schedule, alongside the existing
maxRetries option: initialRetryDelayMillis (default 1000), maxRetryDelayMillis
(default 60000), and retryJitterFactor (default 0.2). The options are available on both
the root client builder and ClientOptions.Builder.
4.11.2
(fix): Fix a thread-safety bug in the generated OAuth and inferred-auth token
caches. OAuthTokenSupplier and InferredAuthTokenSupplier now use
double-checked locking with volatile cache fields, so the token/header
cache (a singleton shared across all request threads) is refreshed exactly
once under concurrent load (single-flight) and cached values are safely
published across threads. The cache-hit path stays lock-free.
OAuthAuthProvider’s existing double-checked locking is corrected by
marking its accessToken/expiresAt fields volatile. No public API
changes; generated code remains Java 8 compatible.
4.11.1
(fix): Fix misleading “Network error” message when deserialization fails. JSON deserialization
errors (e.g. unsupported date formats) are now reported as “Failed to deserialize response”
instead of being incorrectly wrapped as network errors.
(fix): Add RFC 1123 (RFC 2822) date format support to DateTimeDeserializer. Dates like
“Thu, 07 May 2026 14:23:38 +0000” are now parsed correctly.
4.11.0
(fix): Fix URL building for paths with non-slash-separated suffixes (e.g.,
/{Sid}.json). The suffix is now correctly concatenated with the path
parameter value instead of being added as a separate path segment,
which previously caused an extra / before the suffix.
(feat): Add per-request maxRetries override on RequestOptions. A non-null
per-request value overrides the client-wide ClientOptions.maxRetries;
when unset, behavior is unchanged. Mirrors the existing per-request
timeout override pattern and matches the behavior of the TypeScript,
Python, Go, C#, PHP, Rust, and Swift SDKs.
4.10.19
(fix): Remove duplicate JavaDoc descriptions in staged builder implementation methods.
Previously, builder methods would display the field description twice in IDE
inline documentation.