Changelog

2.83.2

(fix): Stop dropping the examples of endpoints whose request body is bytes or a file upload. The IR’s ExampleRequestBody cannot carry those bodies, so such examples read as bodyless and the endpoint lost its snippets and generated tests.

2.83.1

(fix): Honor the x-fern-retries: { disabled: true } extension (retries: { disabled: true } in a Fern definition) at the endpoint level. Requests for those endpoints are now sent exactly once, even when the client or the per-request options configure retries.

2.83.0

(feat): Added a generate-documentation-file config option (default true) so the generated csproj emits XML documentation and the published NuGet package ships lib/<tfm>/<Namespace>.xml, giving consumers IntelliSense. CS1591 is suppressed so enabling documentation does not introduce warnings for undocumented members.

(feat): Added a package-metadata config block for NuGet metadata written into the generated csproj: description, authors, tags, copyright, icon, project-url, repository-url, repository-type, include-source-link (adds Microsoft.SourceLink.GitHub) and include-symbols (produces a .snupkg).

2.82.1

(fix): Global headers typed as a literal<"..."> with an env fallback no longer throw when neither the constructor parameter nor the environment variable is set. The literal is known at compile time, so it is now used as the header’s default value.

(fix): The generated X-Fern-SDK-Version header value is now emitted as a globally qualified reference, so it can no longer be shadowed by a constructor parameter or local that PascalCases to Version (previously error CS1061: 'string' does not contain a definition for 'Current').

2.82.0

(fix): With respect-optional-request-body enabled, examples that omit an optional request body are no longer dropped from the generated snippets and reference.

(feat): Add a respect-optional-request-body option. When enabled, an endpoint whose request body the API does not require takes that body as Body? request = null, so the caller can leave the argument out and the request is sent with no body and no body content type. Examples that supply no body render as client.BulkRefundAsync(). The option defaults to false, so existing signatures and snippets are unchanged.

2.81.1

(fix): Percent-encode ; in query parameter names and values. RFC 3986 permits it, but it remains a legacy parameter separator for many servers, which truncated values such as ?mail2=a@example.com;%20b@example.com at the first ;.

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

2.80.1

(fix): Fix generated mock server tests for examples that omit an optional request body. The stub no longer matches on a Content-Type header that the bodyless request does not send.

2.80.0

(feat): Add opt-in allow-user-agent-app-info config. When enabled, generated clients expose an optional AppInfo client option (Name, Version?, Comment?) whose sanitized product token is appended to whatever User-Agent the SDK would otherwise send ({sdk}/{version} ... {product}/{product-version} ({comment})), following RFC 9110. Disabled by default, so existing generated output is byte-identical, and it composes with include-platform-headers, the configured user-agent template value, and the user-agent-name-from-package fallback. Caller-supplied values are trimmed and encoded (name/version percent-encoded to RFC 7230 tchar; comment delimiters (, ), \ and control characters incl. CR/LF escaped), so untrusted values cannot inject header content. Still overridable by an explicit User-Agent header and suppressed by omit-fern-headers. Works in both unified and non-unified client-options modes; generated code compiles for net462, net8.0, and netstandard2.0.

2.79.4

(fix): Respect the user-agent config template when include-platform-headers is enabled. The structured User-Agent previously always used the NuGet package id, ignoring the configured template.

2.79.3

(fix): Only reference README.md in the generated .csproj when the file actually exists. The <PackageReadmeFile> property and the packed <None Include> item are now guarded with an MSBuild Exists condition, so dotnet pack no longer fails with NU5019 for outputs that do not include a README (e.g. local-file-system output).

2.79.2

(fix): SDKs generated to local-file-system output now stamp the package name and version from the IR’s nuget filesystem publish target (populated by the Fern CLI when --version is passed) into Version.cs, the .csproj <Version> property, and the structured User-Agent header. Previously local-file-system output always produced Version.Current = "0.0.0" and used the root namespace as the User-Agent identity.

2.79.1

(fix): Global headers now honor their client-default value. The constructor initializes the header from the explicit argument, then the environment variable, then the client default. Previously the client default was only applied on the header-dictionary path and was dropped entirely under any-composed multi-scheme auth and endpoint-level security.

2.79.0

(feat): Add support for per-endpoint auth routing. When the API-level auth requirement is ENDPOINT_SECURITY, each endpoint now applies only the auth scheme(s) it declares in its IR security field (OR across the list of requirements, AND within a requirement, and no auth when security is empty), instead of applying every configured credential to every request. Behavior for the ALL and ANY auth requirements (the common cases) is unchanged.

2.78.0

(feat): Support webhook body-hash binding in the generated WebhooksHelper.VerifySignature helper. When a webhook’s HMAC signature configuration declares a bodyHashBinding (as used by providers such as Twilio for JSON bodies), verification now first recomputes an unkeyed hash of the raw request body and compares it, in constant time, against the hash carried in the notification URL’s query parameter, failing closed on a missing or mismatched value before performing the existing HMAC check over the verbatim notification URL. The body-hash algorithm and encoding are independent of the outer HMAC’s. Output is unchanged when no bodyHashBinding is configured.

2.76.6

(fix): Fix a thread-safety bug in the generated OAuthTokenProvider. The token cache is now guarded by a SemaphoreSlim with double-checked locking (the same pattern already used by InferredAuthTokenProvider), so only one caller refreshes the token under concurrent load and cached values are published safely. The cache-hit path stays lock-free.

2.76.5

(fix): When a client is constructed with both a named environment and server URL variables (e.g. Region), the generated client now renders the selected environment’s URL template(s) instead of always using the first (default) environment’s template. Explicitly provided custom base URLs and custom environment values are never overridden.

2.76.4

(fix): Global API headers configured with an env fallback (e.g. X-Twilio-Version with env: TWILIO_VERSION) now fall back to the environment variable in the root client constructor when the parameter is not passed explicitly. Optional headers never throw when both the parameter and the environment variable are missing.

2.77.0

(feat): Add a server-url-variables configuration flag (default true) that controls whether server URL variables declared on the API’s environments are exposed as client options and interpolated into the environment URL template(s) at construction time. When set to false, those client options and the URL-template interpolation are suppressed and the generated SDK falls back to the base-URL behavior from before the feature. Defaults to true, so existing generated output is unchanged.

2.76.3

(fix): The README “Environments” usage example now passes the client options via the clientOptions: named argument so the generated snippet compiles. The root client constructor’s first positional parameter is the auth token string, so the previous new Client(new ClientOptions { ... }) snippet passed ClientOptions where a string? token was expected.