Getting started

PHP SDK overview

The official PHP client for the Envless API. Every workspace, product, project, environment, variable, version, member, role, key and webhook, driven from PHP, with PHPStan and Psalm types and no Composer dependencies.

envless/sdk is the official PHP client for the Envless API. It has every method of the TypeScript SDK, all 113 across 13 namespaces, under the same names, ships a PHPStan and Psalm array shape for every request and response, and has no Composer dependencies.

bash
composer require envless/sdk

Set ENVLESS_TOKEN to an API key and a client needs no arguments at all.

php
use Envless\Envless;

$envless = new Envless();
$workspace = $envless->workspace->get();

foreach ($envless->projects->iterate() as $project) {
    echo $workspace['slug'], ' ', $project['slug'], PHP_EOL;
}

Want one shared client for the whole app, or more than one workspace? See Create a client.

What this is, and what it is not

The PHP SDK administers a workspace from code. It is the PHP twin of @goenvless/sdk: the same methods, the same requests on the wire, the same retries and the same error codes. It is not how a PHP application loads its own variables at boot.

envless/sdk@goenvless/sdk@goenvless/cli
PurposeAdministers a workspace from PHPAdministers a workspace from TypeScriptRuns the envless command, and loads variables into any process
AudienceProvisioning scripts, Artisan and Symfony commands, back offices, CI, platform teamsThe same, on Node, Bun, Deno or WorkersPeople at a shell, CI steps, and apps in any language
AuthAn API key, and nothing elseAn API key, and nothing elseA device session, or a machine key for reads
Shape$envless->projects->create(['name' => 'API', 'slug' => 'api'])envless.projects.create({ ... })envless run -- php artisan serve

If you want your Laravel or Symfony app to read DATABASE_URL at boot, use the PHP runtime, envless/env, or wrap the process with envless run, which decrypts the environment and hands it over as ordinary environment variables, or write a .env file with envless sync. If you want a script that creates a project, adds three environments and seeds their variables, you are in the right place.

Design

Typed for PHPStan and Psalm

Every request body and response is an array shape on Envless\Types, and every method declares the shapes it takes and returns, so PHPStan and Psalm check the keys and the types of each call, and editors complete them.

No dependencies

HTTP is cURL and the encryption is OpenSSL, both standard PHP extensions. PHP 8.2 or newer, and nothing else to install.

Your HTTP client, if you want one

Requests go through cURL by default. Guzzle or any other PSR-18 client plugs in through Envless\Http\Psr18HttpClient, and the retries, the deadline and the redirect rules stay in the SDK.

Honest errors

Every API failure throws Envless\Exception\ApiException carrying the API's stable errorCode, and every transport failure throws Envless\Exception\NetworkException. Both implement Envless\Exception\EnvlessException.

The six things worth knowing up front

A key is bound to one workspace

The workspace comes from the key, never from the request. $envless->workspaces->list() shows you the others the key owner belongs to, but the rest of the SDK only ever acts inside the bound one. Reaching a second workspace means a second client. See Authentication.

Values are ciphertext, always

The server never sees plaintext and cannot encrypt for you. Encrypt before writing, decrypt after reading. See Encryption.

Bodies and results are arrays with the API field names

A request body is one array keyed exactly as the API reference spells it: defaultValue, projectIds, virtualEnvsEnabled. Every result is the decoded array, read as $variable['updatedAt']. The options of a call are named arguments: product:, limit:, timeout:.

Projects live inside products

Project slugs are unique per product, not per workspace. When a slug is ambiguous the call fails with 409 project.ambiguous_product and you disambiguate with product: 'billing'.

Lists come in three flavours

list for one page, listAll for everything, iterate for a stream. See Pagination.

Sync environments with apply, not a loop

$envless->variables->apply() runs a whole change set in one transaction and detects concurrent edits. A loop of single calls does neither.

Namespaces

NamespaceWhat it covers
meThe identity behind the key
workspaceThe bound workspace, and its custom domain
workspacesEvery workspace the key owner belongs to
productsProducts, their projects, and per-product access grants
projectsProjects inside a product
environmentsEnvironments, including public exposure
variablesThe encrypted values, and atomic sync
versionsSnapshots, rollback, and history re-encryption
membersMembership, roles and departures
invitesOutstanding invitations
rolesSystem and custom roles, and permissions
keysThe credentials that reach this API
webhooksEndpoints, secrets, deliveries and replays

Anything not covered by a method is still reachable through $envless->raw->request($path, $method, query: [...], body: [...]), which unwraps the response envelope and throws the same typed exceptions.

Every method has a twin

Each PHP method page links to the same method in the TypeScript SDK, and each one sends exactly the request its TypeScript twin sends. A parity check in the repository replays all 113 methods against the requests the TypeScript SDK records, with no options and with every option set, and fails the build on any difference in the request, the retries, the errors or the result. Every example on the method pages is type-checked with PHPStan at its strictest level and run against a sample API before a release. Ciphertext from this package, the TypeScript, Python and Ruby SDKs, the CLI and the dashboard is interchangeable.