v1.0.0 — first stable release
First stable release. Public API surface is now considered locked; changes
that break source compatibility will trigger a major bump.
Highlights
- Two authentication modes: Personal API token (Bearer, recommended)
and OAuth 1.0a 3-legged (legacy). - Full v2 + v4 endpoint coverage for the platform features most users
reach for: organisations, applications, add-ons, deployments, environment,
domains, billing, instances, load balancers, zones, products, drains,
notifications, webhooks, network groups, operators, pulsar policies,
orchestration, TCP redirections, backups, API tokens, plus
api-bridge.clever-cloud.comrouting. - Live log streaming via Symfony's
EventSourceHttpClient
(Last-Event-IDresume, transparent reconnection). - AutoMapper-driven DTO hydration — readonly, typed, with
#[MapFrom]
for the snake_case ↔ camelCase fields.
Authentication
Credentialsis abstract; build credentials via the named constructors:Credentials::apiToken(string $token)→ApiTokenCredentials—
Authorization: Bearer <token>. Routes every V2/V4 call through
api-bridge.clever-cloud.com. Recommended.Credentials::oauth1(string $consumerKey, string $consumerSecret, ?string $token = null, ?string $tokenSecret = null)→
OAuth1Credentials. HMAC-SHA512 per RFC 5849.
ApiVersion::Bridge+Configuration::bridgeBaseUrlfor routing.OAuthFlowhelper drives the 3-legged exchange.
New resources & methods
$client->apiTokens(Bridge):list / get / create / update / delete.$client->tcpRedirections(V2):list / get / namespaces / add / remove.$client->backups(V4):list / get / restore.$client->drains(V4): full CRUD +enable / disable / restart.$client->notifications(V4): email notification CRUD with event-type
and service filters.$client->webhooks(V4):list / create / delete(raw / slack /
gitter / flowdock formats).$client->networkGroups(V4): list / get / create / delete + members- WireGuard external-peer config download. Operator resources gained
linkNetworkGroup()/unlinkNetworkGroup()helpers.
- WireGuard external-peer config download. Operator resources gained
$client->orchestration(V4): instances + deployments endpoints.$client->operators(V4): facade routing to Keycloak / Matomo /
Metabase / Otoroshi withlist / get / create / update / delete / reboot / rebuild.- Applications add
deploy(?string $commit = null),branches(),
instances(),dependencies()+ add/remove,tags()+ add/remove,
exposedEnv()+ set,addons()+ link/unlink. - Add-ons add
sso(),tags()+ add/remove,migrate(),
listMigrations(),getMigration(),cancelMigration(),
preorderMigration(). - Self adds
update(), SSH keys CRUD, email addresses CRUD, OAuth
consumer CRUD, MFA endpoints,changePassword(). - Organisations add OAuth consumers CRUD,
namespaces(). - Domains add
get(applicationId, fqdn).
Stable enums
Platform-wide values you can drop literal strings for:
Flavor(pico..3XL)DeployType(git / ftp / docker)ApplicationState(full lifecycle +isStable() / isTransient())MigrationStatus(+isTerminal())- Already shipped:
MemberRole,DeploymentAction,DeploymentState,
DrainType,WebhookFormat.
Live log streaming
LogsResource::stream($applicationId, $organisationId, $filters) returns
an iterable LogStream<LogEntry> built on Symfony's
EventSourceHttpClient + ServerSentEvent. Bearer-auth callers transit
api-bridge; OAuth1 callers transit api.clever-cloud.com. Framing,
reconnection, and Last-Event-ID resume are Symfony's responsibility.
HTTP transport
symfony/http-client(^8.0) is now a hard runtime dependency.
php-http/discoverywas removed.nyholm/psr7(^1.8) is a runtime dep — used as the default PSR-7 / -17
implementation.ClientBuilder::withHttpClient()now takes a
Symfony\Contracts\HttpClient\HttpClientInterface; the SDK wires it
internally throughPsr18Clientfor regular calls and
EventSourceHttpClientfor SSE.
Lifecycle hooks
ClientBuilder::onRequest(Closure)runs after URI/body build, before
authentication. Return a modifiedRequestInterfaceto swap it.ClientBuilder::onResponse(Closure)runs on every response (success +
error). Read-only.
Other improvements
- DTO hydration via
jolicode/automapper— readonly classes,#[MapFrom]
for snake_case API fields. - Typed exception hierarchy under
CleverCloudException:
ApiException(+AuthException,NotFoundException,
ValidationException,RateLimitException,ServerException),
TransportException,ConfigurationException,JsonException. All
carrystatusCode,errorCode,requestId, decodedbody. - Retry on 429 (honours
Retry-After) and 5xx (exponential backoff with
configurable jitter) viaRetryPolicy. - PSR-3 structured logging on channel
clevercloud-sdk.
Bug fixes since 0.1.0
- V4 logs URL now
/v4/logs/organisations/{owner}/applications/{appId}/logs
(was/v4/logs/{appId}); owner is required. - V4 operators URL routes through
/v4/addon-providers/addon-{kind}/addons[/{id}](was the made-up
/v4/operators/{kind}/{owner}/...). Ownership comes from credentials. - Pulsar storage policies hit
/storage-policies(was/policy) and
use PATCH (was PUT).list()removed;delete()renamedreset(). - Products endpoints are V2 (not V4) —
ProductsResourcemoved to
Resource\V2\./v4/products/*returned 404. Zone::$tagstyped aslist<string>(was?string). Newid,
outboundIPsfields.Flavor::$memorytyped as
array<string, mixed>(the API returns a nested object).- Application restart/deploy now send
{}JSON body with
Content-Type: application/jsonso the API doesn't return 415. - SSE stream errors surface as typed SDK exceptions
(AuthException/NotFoundException/ServerException) instead of
silently ending iteration.
Removed
PageIteratorand the entiresrc/Pagination/directory. It was never
wired into any list endpoint. Cursor pagination will land later when
Clever Cloud's V4 cursor responses stabilise across endpoints.
Breaking changes since 0.1.0
Credentialsis abstract; replacenew Credentials(...)with
Credentials::oauth1(...)orCredentials::apiToken(...).ClientBuilder::withHttpClient()now expects a Symfony
HttpClientInterface(was PSR-18ClientInterface).LogsResource::stream()signature changes — owner is required, returns
a Symfony-backedLogStream.OperatorsResourcepaths and arguments changed.PulsarPoliciesResource:list()removed,delete()→reset(),
update()uses PATCH.