Changelog

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

1.19.0

(feat): Add webhook body-hash binding verification before HMAC signature checks.

(fix): Fix generated verify_signature webhook helper raising instead of returning false when signature_header or signature_key is an empty string. An empty key was passed to OpenSSL::HMAC.digest, which raises on OpenSSL 3.x; the input guard now fails closed on empty (not just nil) signature header and key, matching the never-raise contract.

1.18.2

(fix): Fix a thread-safety bug in the generated OAuthProvider and InferredAuthProvider. The token cache is now guarded by a Mutex with double-checked locking, so only one thread refreshes the token under concurrent load (e.g. multi-threaded servers like Puma or Sidekiq). The cache-hit path stays lock-free.

1.18.1

(fix): When a client is constructed with both an 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 environment’s template. For multi-host environments, every host’s URL is formatted from the selected environment’s templates. An explicitly provided custom base URL or environment is never overridden.

1.18.0

(feat): Endpoint methods now include a usage example in their YARD doc comment via the @example tag, so IDEs surface a code snippet on hover.

1.17.8

(fix): Only emit the internal URL-encoded request module (and its root require_relative) when an endpoint actually sends an application/x-www-form-urlencoded body. Previously the require_relative ".../internal/url_encoded/request" line was emitted unconditionally; SDKs generated with a build that shipped the require but not the as-is file (e.g. an API with no form-urlencoded endpoints) failed to load with a LoadError. The require and its file are now driven by the same usage check, so they can never ship apart.

1.17.7

(fix): Revert the smart-casing digit/word boundary behavior introduced in 1.15.5. snake_case names keep a digit run fused to the following word (conversations_v2configuration), restoring pre-1.15.5 output. The behavior will become opt-in via the new smart-casing-digit-word-boundary option in generators.yml once the generator consumes the IR version that carries the setting.

1.17.6

(fix): Endpoints now send service- and endpoint-level headers whose types are literals (e.g. Accept-Encoding: literal<"gzip">). Previously these headers were silently dropped for endpoints without a request wrapper, and service-level literal headers were never sent at all. Caller-supplied values via the request params still take precedence over the literal defaults.

1.17.5

(fix): Cap generated type filenames at 100 characters so gem build no longer fails with Gem::Package::TooLongFileName (RubyGems packages into a tar format whose header caps filenames at 100 chars). Deeply nested inline types — such as anonymous oneOf variants — could previously overflow this limit. When a name is too long it is truncated and a short deterministic hash is appended to keep it unique. This changes only the filename and its require_relative; the module/class name is unchanged, so it is non-breaking for consumers, who reference the constant rather than the file.

1.17.4

(fix): Send request bodies declared with the application/x-www-form-urlencoded content type (e.g. OAuth token endpoints) as form-urlencoded instead of JSON. A new Internal::UrlEncoded::Request encodes the body with URI.encode_www_form and sets the Content-Type: application/x-www-form-urlencoded header.

1.17.3

(fix): Expose non-literal global headers without a client default as root client constructor parameters. Headers with a declared env default to that environment variable (e.g. version: ENV.fetch("MY_API_VERSION", nil)), and the header is only sent when the value is non-nil. Previously such headers were omitted entirely and could only be sent via per-request additional_headers.

1.17.2

(fix): Serialize request bodies declared as aliases of objects through the aliased class so wire names are applied. Previously the raw params hash was sent, so properties whose Ruby name differs from the API wire name (e.g. display_name vs. displayName) were sent with the wrong key.

1.17.1

(fix): Send grant_type: "client_credentials" in the OAuth token request when the token endpoint’s grant_type property is a non-literal string. Previously the property was omitted (when optional) or surfaced as a required constructor parameter (when required), so token endpoints that require grant_type rejected the request.

1.17.0

(feat): Add support for auto-generating an idempotency-key request header. This is now driven entirely by the IR (SdkConfig.idempotencyKeyGeneration), resolved once by the CLI from the auto-generate-idempotency-key generator config key, so the header name and the set of eligible HTTP methods are read identically across every generator. When enabled, the generated SDK attaches the configured header (defaulting to Idempotency-Key) on the configured methods (defaulting to POST and PUT) with a freshly generated UUIDv4 (SecureRandom.uuid) at request time. For endpoints that declare a matching idempotency header the caller-supplied value wins and the generated UUID is only the fallback. When the IR does not enable the feature, generated output is unchanged.

1.16.0

(feat): Add support for server URL variables (e.g. region/edge routing). Server variables defined on the API’s environments are now exposed as optional string keyword arguments on the client initializer and interpolated into the base URL(s) when provided, falling back to each variable’s default. Reserved option names are de-collided by prefixing with server_url_ (e.g. a variable named environment is exposed as server_url_environment).

1.15.5

(fix): Fix smart-casing snake_case names dropping the word boundary after a number. Sub-client accessors and methods like ConversationsV2Configuration now generate conversations_v2_configuration instead of conversations_v2configuration.

1.15.4

(fix): Decompress gzip and deflate encoded response bodies when the Accept-Encoding header is set explicitly on the request. Net::HTTP disables its transparent response decoding as soon as the caller sets an Accept-Encoding header, so responses to requests with a spec-defined Accept-Encoding: gzip header were previously returned as raw gzip bytes.

1.15.3

(fix): Fix reference.md endpoint titles to show path parameters in keyword-argument form (e.g. fetch_store(store_id:) instead of fetch_store(store_id)). Generated Ruby methods only accept keyword arguments, so the previous positional-looking titles were misleading.

1.15.2

(fix): Fix OAuth (and inferred-auth) access tokens never being refreshed on expiry. The token was resolved once at client construction and baked into the RawClient’s static default headers, so every subsequent request kept sending the original (eventually stale) token until the client was reconstructed. The RawClient now receives the auth provider and resolves its auth_headers on every request, so the provider’s existing refresh logic runs before each call. Api-key/basic/ bearer/no-auth flows are unaffected (no provider is passed, so header resolution is a no-op).

1.15.1

(chore): Upgrade the generator to consume IR v67.