This release corrects resources that never worked against the real Clever Cloud
API. Every path, payload shape and status code below was verified by calling the
live API, not inferred from documentation.
The major bump is deliberate. 1.0.0 promised that breaking source compatibility
would trigger one, and this release removes public symbols. Several of them
described endpoints or fields that do not exist, so code using them was already
failing at runtime; but Deployment::$author and ProductsResource::countries()
compile today and will not after upgrading. Read the breaking changes before
bumping.
Breaking changes
Resource\V2\LogsResourceis nowResource\V4\LogsResource. No
compatibility alias is provided. The class targeted a V2 path the API does not
serve, so every call returned 404 and no working code can be relying on it.
$client->logsis unchanged.Model\Countryis removed. It described a shape the API never sends. See
countries()below.ProductsResource::countries()returnsarray<string, string>instead of
list<Country>: a map of upper-case English country name to ISO 3166-1
alpha-2 code, which is what the endpoint actually answers.LogEntry::$streamis removed, replaced by$service. Constructor
parameter order changed, so positional construction ofLogEntrybreaks.User::$firstnameandUser::$lastnameare removed./v2/selfreturns a
singlenamefield; those two were alwaysnull.Deployment::$authoris now?DeploymentAuthorinstead of?string.InstancesResourceis now V2-based and only exposeslist(). The 1.0.0
version targeted V4 routes (/v4/products/instances*) that Clever Cloud does
not expose, so every method returned 404. The redundant
get(type[, version]),flavors(type), andtypes()methods are removed;
calllist()and filter client-side on$instanceType->typefor per-type
data. (The catalogue payload is the same as$client->products->instances().)
Fixed
- Log streaming worked for nobody.
LogsResourcebuilt
/v2/organisations/{org}/applications/{app}/logs, which answers 404. The real
endpoint is/v4/logs/organisations/{ownerId}/applications/{appId}/logsand
speakstext/event-stream. There is no/selfform, so the personal
organisation is addressed by its ownuser_<uuid>id; passing anullowner
now resolves it throughGET /v2/self, costing one extra request. LogEntrymapped almost nothing. Its#[MapFrom]attributes asked for
instance_id,application_idanddeployment_idwhile the API sends
camelCase, so those three were alwaysnull. Properties now match the wire
format, and the previously droppedid,priority,commitId,regionand
versionare exposed.LogsResource::query()could not work as a plain GET, since the endpoint
only speaks SSE. It now consumes the stream and stops early. It also takes a
$maxDurationSecondsbudget (default 10), which is what actually guarantees
the method returns: the endpoint never closes an idle stream, it emits
HEARTBEATforever, and no combination ofsince,untilandlimitmakes
it hang up. Pass asincefilter, or the call degenerates into a live tail.AddonsResource::plans()requested/v2/products/addonproviders/{id}/plans
(404). Plans are nested in the provider payload; it now reads them from there.ProductsResource::countries()threw aTypeErrorbecause it hydrated a
JSON object as a list of models.DeploymentsResourcelistings always threw aTypeError: the API sends
authoras an object, not a string.ApiTokensResourcepaths and documented auth mode were both wrong. The
routes are/api-tokens, not/v2/api-tokens(404). And the gateway requires
OAuth 1.0a, answering400 must start with "OAuth "for a Bearer header, the
opposite of what the docs claimed. Minting a Bearer token is what these
endpoints are for, so a token-authenticated client cannot manage tokens.Usermapping had the same snake_case defect asLogEntry, leaving
preferredMfa,hasPassword,canPay,emailValidatedandcreationDate
null on every response.- Documentation claimed logs required OAuth 1.0a and that API tokens always
got a 404. That was a misdiagnosis of the broken path: Bearer tokens stream
and query logs correctly throughapi-bridge.clever-cloud.com. - The OAuth 1.0a CLI example sent
oobas its callback, which Clever Cloud
rejects with HTTP 500. It now sends a real URL and readsoauth_verifierback
from the browser's address bar, withCC_OAUTH_CALLBACKto override the host. api-bridgedemo and docs now explain the13502callback rejection. The
callback is validated against the scheme and host of the consumer's Base URL
(port and path are not checked), so a consumer registered onhttp://refuses
anhttps://callback. The demo surfaces the mismatch and theclever oauth-consumers updatecommand to fix it instead of only echoing the error.READMEno longer credits PHP 8.5 with features that landed earlier: enums
(8.1), readonly classes (8.2), property hooks and asymmetric visibility (8.4).
The 8.5 floor is a support choice, not a technical requirement.READMEno longer claims Clever Cloud's full v2 + v4 surface, which its own
Roadmap section contradicts, and its status block now reflects 2.0.
Added
docs/- full reference documentation. Resource pages with verified
signatures + HTTP paths, guides for getting started, authentication,
configuration, error handling, live log streaming, and testing patterns.Model\DeploymentAuthorDTO (id,name).Deployment::$instances, which the payload carries and the model dropped.LogStreamaccepts an optional$maxDurationSecondsto bound iteration,
checked on every chunk so heartbeat-only traffic still honours the budget.- Regression tests pinning the live shapes: heartbeat-only streams must not trap
query(),LogEntrycamelCase fields must populate, and the country catalog
must stay a map.
Changed
composer phpstannow runs with--memory-limit=1G: PHPStan crashed on the
default 128M CLI limit.
Upgrading from 1.0.0: read the breaking changes above first. Most of the
removed symbols described endpoints or fields the API never served, so code
using them was already failing at runtime, but Deployment::$author and
ProductsResource::countries() compile today and will not after upgrading.
Full changelog: v1.0.0...v2.0.0