2.2.0

(feat): Add omitFernHeaders configuration option. When enabled, Fern platform headers (X-Fern-Language, X-Fern-SDK-Name, X-Fern-SDK-Version, User-Agent) are omitted from generated SDK requests.

2.1.12

(fix): Fix WireMock datetime mismatch in wire tests. The mock-utils package generates datetime query parameter values with milliseconds (e.g., 2022-01-02T00:00:00.000Z) via Date.toISOString(), but PHP’s DateTimeInterface::RFC3339 format omits fractional seconds (e.g., 2022-01-02T00:00:00Z). Since WireMock’s equalTo is an exact-match, the stubs never fired. Now strips zero milliseconds from WireMock datetime query parameter values to match the PHP SDK’s serialization format.


2.1.11

(chore): Add concurrency configuration to generated CI workflow with cancel-in-progress: false to prevent stacked runs from being cancelled when a newer run starts.


2.1.10

(fix): Fix serialization and deserialization of boolean values in union types. (Matches existing fix for floats.)

2.1.9

(fix): Re-throw errors after logging for README.md and reference.md generation failures. Documentation generation errors now break the generation flow so they are treated as important to fix.

2.1.8

(fix): Fix dynamic snippets to include global headers in generated code examples. Previously, required global headers (e.g., X-Organization-ID) configured via x-fern-global-headers were missing from dynamic snippet output. Also fixes header value lookup to use wire values instead of a non-existent property.


2.1.7

(chore): Improve error logging for README.md and reference.md generation failures. The generator now logs the actual error message and stack trace instead of a generic message, making it easier to diagnose generation issues.


2.1.6

(chore): Parallelize endpoint snippet generation in populateSnippetsCache(). All endpoints are now processed concurrently via Promise.all instead of sequentially, reducing snippet generation time for large APIs.


2.1.5

(chore): Standardize WireMock configuration to use WIREMOCK_URL environment variable (e.g., http://localhost:8080) instead of a hardcoded URL. Docker Compose now uses dynamic port mapping (0:8080) to avoid port conflicts when running multiple SDK tests in parallel. The bootstrap script discovers the assigned port and sets WIREMOCK_URL automatically. Falls back to http://localhost:8080 if the variable is not set.


2.1.4

(fix): Fix PHP 8.5 deprecation warning for ReflectionProperty::getDefaultValue() called on properties without a default value. Now checks hasDefaultValue() before calling getDefaultValue() in JsonSerializableType::jsonDeserialize().

2.1.3

(chore): Use generator-cli JS API directly instead of subprocess spawning. Remove generator-cli from Docker image since it is now bundled via esbuild.


2.1.2

(fix): Fix generateClientInterfaces to generate interfaces for aggregator-only clients (clients that hold sub-client properties but have no direct API endpoints). Previously, these clients were skipped, leaving the top-level client and intermediate grouping clients without interfaces.

Interfaces now include typed getter method signatures for each sub-client (e.g., getUsers(): UsersClientInterface), and the corresponding client classes implement these getters.

2.1.1

(fix): Fix PHPStan static analysis errors in core runtime classes. Tightens return types (e.g., castKey now returns int|string instead of mixed), adds missing null checks, and improves PHPDoc annotations across JsonSerializer, JsonDeserializer, and Utils. Also fixes BaseApiException::__toString() to use getCode() instead of direct property access and print_r() for non-scalar body values.

(fix): Add of object bound to pagination template generics (CursorPager, OffsetPager) to satisfy PHPStan’s requirement for clone on object types.


2.1.0

(fix): Fix wire test generation for types with required constructor fields. Previously, the test generator would pass empty arrays [] as constructor arguments when no example values were provided for required fields (e.g., new SomeType([])). Now generates appropriate placeholder values based on each field’s type (e.g., new SomeType(['ids' => [1]])).

(feat): Add support for fileDownload (application/octet-stream) and bytes response types. Previously, endpoints returning binary data would throw an error at runtime because no success handling was generated. Now these endpoints return the raw response body as a string.


2.0.0

(feat): Introduce PSR-7/17/18 HTTP interfaces for framework-agnostic HTTP client support.

This restores the PSR-7/17/18 agnostic approach that was temporarily reverted in v1.30.0. The SDK now supports any PSR-18 compliant HTTP client (Guzzle, Symfony HttpClient, etc.) and uses php-http/discovery to automatically find an installed client at runtime.

Breaking changes are minimal, but do exist:

  • Guzzle is no longer a hard dependency (moved to suggest/require-dev)
  • Per-request timeout behavior may differ between HTTP client implementations (currently supported for Guzzle and Symfony)
  • Code that directly catches GuzzleHttp\Exception\RequestException will require a refactor

Migration: Existing Guzzle users should be largely unaffected as Guzzle implements PSR-18. For custom HTTP clients, ensure they implement PSR-18 interfaces.

1.30.0

(fix): Temporarily revert PSR-7/17/18 HTTP interfaces back to hard Guzzle dependency. This restores the pre-1.27.0 behavior where the SDK requires Guzzle as a hard dependency. Users should expect this to be re-introduced as a breaking change in v2.0.0.

This change reverts the framework-agnostic HTTP client support introduced in v1.27.0, restoring Guzzle middleware-based retry logic and direct Guzzle dependency.