forxer/ovh-sdk
forxer/ovh-sdk is a PHP client for the OVH API that handles authentication, request signing, and responses behind a clean, Laravel-friendly interface, making it easy to manage domains, servers, and cloud resources directly from your application code.
composer require ovhcloud/ovh-php-sdk # or the Laravel wrapper, if used
php artisan vendor:publish --tag=ovh-sdk-config
application_key, application_secret, consumer_key, and endpoint (ovh-eu, ovh-ca, ovh-us, …). Authentication is handled for you: on first call the SDK hits GET /auth/time, computes a clock delta, caches it for an hour, and signs every subsequent request.use OvhSdk\Enums\TaskStatus;
$ids = $client->dns()->zone('example.com')->tasks()->ids([
TaskStatus::Todo,
TaskStatus::Doing,
]);
new the client in controllers; the auth time-delta cache is per-instance and is worthless if you rebuild the client on every request.ids() / list() is whitelist-oriented. Pass only statuses OVHcloud will actually accept; build the array from TaskStatus cases and filter out anything you aren't sure about. These methods now validate the filter client-side before sending, so a bad filter fails fast and locally.CouldNotDecodeResponse (subclass) → CouldNotReadResponse. Put the more specific catch first:
try {
$tasks = $client->dns()->zone($zone)->tasks()->list($statuses);
} catch (CouldNotDecodeResponse $e) {
// body wasn't JSON (empty body included) — often transient, retry
$previous = $e->getPrevious(); // JsonException, if any
throw $e; // or retry with backoff
} catch (CouldNotReadResponse $e) {
// valid JSON, wrong shape — a bug or API contract change, do not retry blindly
report($e);
throw $e;
}
CouldNotDecodeResponse is retryable (empty/HTML body from a proxy or hiccup); CouldNotReadResponse is not (scalar where a list/object was expected means the contract changed). Wire this into a queued job's retryUntil/backoff rather than a blanket catch (\Throwable).TaskStatus::Problem on the read path. You cannot filter for it, but a task returned by OVHcloud can still carry it. Map it in your domain model and surface it in monitoring — don't assume the enum case is unreachable.Http::fake) and assert on the SDK exceptions, not raw JsonException or TypeError. This keeps tests aligned with the new contract.CouldNotDecodeResponse extends CouldNotReadResponse; a catch (CouldNotReadResponse) placed first swallows the decode case and you lose the ability to retry only transient failures.JsonException catch is dead code. A non-JSON successful body no longer throws JsonException; it throws CouldNotDecodeResponse. Reach the underlying JsonException via getPrevious().[]; it now throws CouldNotDecodeResponse. Any code that treated "no content" as "no results" will start failing — decide explicitly whether to retry.tasks()->ids() / list() reject TaskStatus::Problem with CouldNotFilterZoneTasks (an InvalidArgumentException) before the request is sent. OVHcloud's schema lists the value but answers 400 Invalid inputs — so this is a client-side guard, not a server error. Don't catch BadRequestException for it anymore.GET /auth/time doesn't return a JSON integer, the SDK throws instead of falling back to 0. The old fallback produced a wrong delta that was cached for an hour, so every signature failed — if you see a burst of signature errors after a deploy, check that endpoint before blaming credentials.endpoint at runtime (e.g. multi-region jobs) means a fresh client and a fresh time fetch.How can I help you explore Laravel packages today?