> 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

## September 30, 2026

## 5.34.2

**`(fix):`** Accept an `async_token` callable on the async root client when OAuth client credentials are
configured with a token override. Previously only a synchronous `token` callable could be
supplied in token mode, so resolving the token blocked the event loop on every request. The
async client now exposes `async_token: Optional[Callable[[], Awaitable[str]]]`, adds a
constructor overload for it, and forwards it to `AsyncClientWrapper`.

**`(fix):`** When `async_token` is set on an async client, the synchronous `token` is no longer resolved
for async requests. `AsyncClientWrapper.async_get_headers()` now calls
`get_headers(include_token=False)` and uses only the awaited token, so a blocking `token`
callable never runs on the event loop.

## September 29, 2026

## 5.34.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 28, 2026

## 5.34.0

**`(feat):`** XML-encoded (TwiML) models now carry inline documentation on their user-facing APIs: the
`__init__` of text-bearing models and every fluent child method (`say.break_(...)`) document
each parameter from the API definition's property descriptions, plus `**extra_attributes`.

## 5.33.2

**`(fix):`** Also emit the SPDX `license` in `[tool.poetry]` alongside the PEP 639 `[project]` license. Poetry 1.x
(including the `poetry` version pinned in the generated publish workflow) ignores the `[project]`
table, so since 5.32.0 packages built with it were published to PyPI without any license metadata.

## 5.33.1

**`(fix):`** Annotate generated WebSocket `__iter__` / `__aiter__` methods with `typing.Iterator[<Socket>Response]` /
`typing.AsyncIterator[<Socket>Response]` so type checkers infer iterated messages as the response union
(matching `recv()`) instead of `bytes | <Response>`.

## September 24, 2026

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

## 5.32.1

**`(fix):`** Stop emitting deprecated `License ::` PyPI classifiers alongside the PEP 639 `[project] license`
expression; modern setuptools rejects the combination. Inline `metadata.license: "MIT"` /
`"Apache-2.0"` now also writes the standard license text to `LICENSE` and declares it via
`license-files = ["LICENSE"]`.

## September 23, 2026

## 5.32.0

**`(feat):`** License metadata is now emitted in the `[project]` table of the generated `pyproject.toml`
following PEP 639: `metadata.license: "MIT"` / `"Apache-2.0"` produce `license = "<SPDX>"`,
and `metadata.license: { custom: "./LICENSE" }` produces `license-files = ["LICENSE"]`.
When the custom license file is recognized (Apache-2.0, MIT, BSD, GPL, MPL, ISC — same
heuristics as the Java generator), `license = "<SPDX>"` and the matching PyPI classifier are
emitted alongside `license-files`.

## 5.31.2

**`(fix):`** Fix multipart requests where a `list<file>` property declares a `content-type`. The generated
client now applies `core.with_content_type` to each file in the list instead of passing the
whole list to a single call, which failed mypy and would have sent the list as one part.

## September 22, 2026

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

## September 21, 2026

## 5.31.0

**`(feat):`** Object types carrying IR `encoding.xml` metadata (e.g. Twilio TwiML verbs imported from an OpenAPI
`xml` object) now generate a `to_xml()` method (and `__str__`) that serializes the model as an XML
element: properties marked as attributes become XML attributes, the text property becomes the element
body, and remaining properties are emitted as ordered child elements, honoring wire names,
namespaces/prefixes, wrapped lists and attribute list separators. A `core/xml_utilities.py` helper is
emitted only when the API contains XML-encoded types.

**`(feat):`** XML-encoded object types with a list-valued child element property also generate fluent builder
methods: `append(child)` and one `<tag>(text, *, attributes...)` method per child element type that
constructs the child, appends it and returns it (e.g. `response.say("Hello", voice="Polly.Joanna")`,
`say.break_(time="100ms")`). Method names derive from the XML tag; on a clash with a field they get an
`add_` prefix (`Dial.add_number`, `Message.add_body`).

**`(feat):`** XML-encoded types match the ergonomics of hand-written XML helper libraries: text-bearing elements
accept their body positionally (`Say("Hello", voice="man")`), constructors and builder methods accept
arbitrary `**extra_attributes: str` that are rendered as XML attributes (`Say("Hi", foo="bar")` ->
`<Say foo="bar">Hi</Say>`), and `str()` of a root element (one never nested in another XML type)
includes the `<?xml version="1.0" encoding="UTF-8"?>` declaration. `to_xml(xml_declaration=...)` is unchanged.

**`(feat):`** XML-encoded object types also generate a `from_xml(xml)` classmethod that parses an XML string (or a
parsed element) back into the model: the root element name is validated, attributes/text/child
elements map to their properties (honoring namespaces, wrapped lists and list separators), child
unions dispatch on the element name, and scalar/enum values are converted by the model's normal
validation. Attributes the schema does not declare are kept as extra attributes and child elements it
does not declare are preserved as `XmlElement` nodes (also addable via `add_child(...)`), so
`Model.from_xml(model.to_xml())` round-trips. Parsing uses the standard library with DOCTYPE
declarations rejected; malformed input raises `ValueError`.

## September 15, 2026

## 5.30.2

**`(fix):`** Fix the generated OIDC publish workflow in `ci.yml` so the `pypi` GitHub Environment URL
points to the configured `package-name` (`https://pypi.org/p/<package-name>`) instead of
`github.event.repository.name`.

## September 14, 2026

## 5.30.1

**`(fix):`** The generated README only documents pagination (`SyncPager`, `iter_pages()`) when paginated
clients are actually generated, so the README and `list()` return types stay in sync.

## September 8, 2026

## 5.30.0

**`(feat):`** Add a `license_header` custom config option that emits the configured text as a comment
at the top of every generated Python file, above the auto-generated notice.

```yaml
config:
  license_header: |
    Copyright 2024 Acme, Inc.
    Licensed under the Apache License, Version 2.0.
```

## September 4, 2026

## 5.29.4

**`(fix):`** Fix the generated `tests/utils/test_http_client.py` failing when `retry_status_codes: recommended`
is configured. The retry-status expectations in the test are now derived from the configured mode
instead of always asserting the legacy set (which includes 500, 501 and 599).

## August 31, 2026

## 5.29.3

**`(fix):`** Cache Pydantic field alias metadata per model class instead of rebuilding the field name to alias maps on
every validation. The `mode="before"` validator now skips copying the input mapping when no key needs to be
rewritten, and `parse_obj_as` reuses the cached metadata instead of rescanning fields on each call. This
roughly halves the parsing cost of streaming responses, where the validator runs once per nested model per
event. As a result the validator can now hand the caller's own `dict` to Pydantic rather than a copy of it;
Pydantic does not mutate or retain that mapping, so parsed models are unaffected.

## August 26, 2026

## 5.29.2

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

## August 20, 2026

## 5.29.1

**`(fix):`** Fixed generated WireMock stubs for OAuth client credentials APIs whose token endpoint is
itself marked as authenticated: the token (and refresh) endpoint stub no longer requires
an `Authorization` header, since the token request is made to obtain the token and cannot
carry one yet.

## 5.29.0

**`(feat):`** Add `stream_abstraction`. With it enabled, streaming endpoints return a `Stream[T]`
(`AsyncStream[T]` for async clients) rather than a plain iterator, mirroring the TypeScript SDK's
`core.Stream`. Iterating the stream still yields the parsed payloads, while `with_metadata()`
yields them wrapped in a `StreamEvent` that also exposes the server-sent event `id`, `event` and
`retry` fields — `for event in client.completions.stream(...).with_metadata()` — so reading an
event id no longer requires dropping down to `with_raw_response`. The request is still only
issued once the stream is iterated, the stream owns the underlying response and releases it when
exhausted, closed or exited as a (asynchronous) context manager, and the raw client's `data` is
the same stream. `AsyncStream` is awaitable, so `await client.completions.stream(...)` and
`async for chunk in client.completions.stream(...)` both work. Defaults to `false`, so signatures
and snippets are unchanged until you opt in.

**`(fix):`** Server-sent events carrying no data, such as comment-only and retry-only frames, are skipped
instead of being parsed as a payload, which previously failed model construction and logged a
warning.

**`(feat):`** `HttpResponse` and `AsyncHttpResponse` expose the underlying `httpx.Response` through a public
`response` property.

**`(fix):`** Fix the generated async examples for streaming endpoints, which awaited the method call —
`response = await client.completions.stream(...)` — even though it returns an async generator and
raises `TypeError: 'async_generator' object can't be awaited`.

## August 13, 2026

## 5.28.0

**`(feat):`** Add `respect_optional_request_body`. With it enabled, an endpoint whose request body the API does
not require defaults that body to the `OMIT` sentinel — `batch_refund(request: Sequence[RefundRequest] = OMIT)`
rather than `request: Optional[Sequence[RefundRequest]]` — so "not passed" stays distinct from an
explicit `None`, and a body left out means the request carries no content and no `Content-Type`.
Examples that supply no body render as `client.batch_refund()`. When the body inlines into keyword
arguments instead, leaving all of them out sends no body rather than an empty `{}`. Defaults to
`false`, so signatures and snippets are unchanged until you opt in.

## August 10, 2026

## 5.27.1

**`(fix):`** Accept a plain string for the root client's `token` parameter when OAuth client credentials
are configured with a token override. The constructor overload, implementation signature, and
docstring previously typed `token` as `typing.Callable[[], str]` only, even though the client
wrapper accepts `typing.Union[str, typing.Callable[[], str]]` at runtime and the generated
example passes a string literal, so type checkers rejected the documented usage.

## August 9, 2026

## 5.27.0

**`(feat):`** Add an opt-in `prefer_explicit_auth` configuration option. When enabled (and the API composes
OAuth client-credentials with basic auth via `auth: any`), auth credentials passed
explicitly to the client constructor take precedence over environment-variable
defaults when selecting the auth scheme — e.g. explicitly provided basic auth
credentials win over OAuth client ID/secret environment variables. Disabled by
default, so existing generated output and runtime behavior are unchanged.

## August 8, 2026

## 5.26.1

**`(fix):`** Fixed WireMock stubs for wire tests of APIs with `auth: any` combining Basic and
OAuth/Bearer schemes: stubs now accept either Authorization form instead of
requiring the exact Basic header the client may not send.

## July 31, 2026

## 5.26.0

**`(feat):`** Add an `encode_path_params` config option (default `false`). When enabled, path parameter
values are percent-encoded when substituted into the request path, so a value containing `/`
or `..` can no longer change which endpoint the request resolves to. The default `false`
preserves the existing (unencoded) behavior; TypeScript, Go, Java, and C# already encode path
params.

## 5.25.0

**`(feat):`** Add opt-in `allow_user_agent_app_info` config (camelCase alias `allowUserAgentAppInfo`).
When enabled, the generated client accepts an optional `app_info`
(`{"name": ..., "version"?: ..., "comment"?: ...}`) constructor argument whose product
token is appended to the `User-Agent` header
(`{sdk}/{version} ... {product}/{product-version} ({comment})`), following RFC 9110.
Disabled by default, so existing generated output is unchanged. It composes with
`include_platform_headers`, the `user-agent` template config, and the default
`{package}/{version}` value, and survives the `runtime_version` path. Caller-supplied
values are sanitized (name/version token-encoded, comment delimiters and control
characters escaped), and it is still overridable by an explicit `User-Agent` header and
suppressed by `omit_fern_headers`.

## 5.24.2

**`(fix):`** Fix two issues with the opt-in `allow_user_agent_app_info` client option:

* The `app_info` constructor parameter no longer leaks a bare positional `None`
  into generated usage snippets and docstrings, which produced invalid Python
  (a positional argument after keyword arguments). It remains an optional keyword
  argument defaulting to `None`.
* Non-ASCII characters in the `app_info` comment are now percent-encoded (UTF-8).
  Previously they were passed through into the `User-Agent` header, causing httpx
  to raise `UnicodeEncodeError` on every request.

## July 30, 2026

## 5.24.1

**`(fix):`** Respect the `user-agent` config template when `include_platform_headers` or
`runtime_version` is enabled. The structured User-Agent previously always used the
package name and version, ignoring the configured template.

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