Getting started

Changelog

Version history for envless/sdk, the PHP SDK.

Version history for envless/sdk, the PHP client for the Envless API, published on Packagist. Keep it current for the latest coverage, security patches and type fixes. When a newer version is out, the client says so once on a terminal, with the composer update command to run.

The TypeScript SDK, @goenvless/sdk, has its own changelog, and so do the Python SDK and the Ruby SDK. They cover the same API, and a change to one lands in the others.

Unreleased

Next release

Changed

  • Each list method takes only the options its route reads, the same set as its TypeScript twin: search: and roleId: on members lists, search: and sortBy: on roles lists, search: on invites lists, search: and order: on products, products->listProjects(), keys and webhooks lists, those plus product: on projects and environments lists, product: on variables and versions lists and their history and entries, and only limit: and offset: on workspaces and products->access lists. Passing an option the route never read now fails with PHP's Unknown named parameter error instead of being ignored
  • variables->getById(), updateById(), deleteById(), versions->get() and versions->rollback() no longer take product: or send ?product=, since the id already names the project

Added

  • isSecret on VariableInput and VariablePatch, and name on an ApplyUpdateEntry, which renames the variable in the same variables->apply() transaction
  • roleId: on members->list(), listAll() and iterate(), and sortBy: on the roles lists

Fixed

  • Envless::isCiphertext() no longer makes PHPStan report that a call "will always evaluate to true" when it is given a string. It now declares @phpstan-assert-if-true =string, so PHPStan still narrows a string|null value to string inside the if without treating the call as a type test every string passes. Psalm reads the unchanged @psalm-assert-if-true string

Changed

  • The package links its own documentation, this section, with a guide and a page for each of the 113 methods. Every example on those pages is type-checked with PHPStan and run against a sample API before a release

Initial release. The PHP twin of the TypeScript SDK, covering 100% of the public HTTP API: all 113 methods across 13 namespaces, under their TypeScript names. A parity check replays every method 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.

Client

  • Envless\Envless with a readonly property for every namespace: me, workspace (with workspace->domain), workspaces, products (with products->access), projects, environments, variables, versions, members, invites, roles, keys, webhooks
  • new Envless() reads ENVLESS_TOKEN and ENVLESS_API_ENDPOINT for whatever you leave out. Envless::init(...) configures a shared client once at startup, Envless::getClient() returns it, building one from the environment on first use, and Envless::resetClient() drops it
  • A request body is one array keyed by the API's own field names, and every result is the decoded array. The options of a call are named arguments: product:, limit:, offset:, search:, order:, status:, reattempt:, and timeout: on every method
  • $envless->raw->request($path, $method, query:, body:) reaches an endpoint no method wraps yet, with the client's key, base URL, timeout and retries
  • Bring your own transport: Guzzle or any PSR-18 client through Envless\Http\Psr18HttpClient, or anything implementing Envless\Http\HttpClient. Redirects, retries and the deadline stay in the client
  • A client is immutable once built and keeps one connection alive, while POST and PATCH always start on a fresh one so a dropped connection never makes them run twice. After a fork() the child opens its own

Pagination

  • Every collection has list for one page as an Envless\Result\Page, listAll for everything as an array, and iterate, a Generator that fetches the next page only when the loop gets there
  • Secondary collections get their own trio: products->listProjects, products->access->list, variables->listHistory, versions->listEntries, webhooks->listDeliveries, each with listAll* and iterate* forms
  • The walk ends on hasMore being false or an empty page, and advances by the items actually received

Errors

  • Envless\Exception\ApiException carries the stable errorCode plus status, resource, field, requestId and retryAfterSeconds, with predicates for the common branches: isAuth(), isScopeMissing(), isValidation(), needsUpgrade(), isNotFound(), isConflict(), isRateLimited()
  • Envless\Exception\NetworkException for transport failures, with isTimeout() when the deadline passed. Envless\Exception\DecryptionException and Envless\Exception\WebhookVerificationException for the crypto and webhook helpers, and Envless\Exception\InvalidArgumentException for a mistake in the call itself. All of them implement Envless\Exception\EnvlessException
  • GET, HEAD, PUT and DELETE are retried on 408, 429, 500, 502, 503 and 504 with exponential backoff capped at 30 seconds, honouring Retry-After. POST and PATCH are never retried
  • timeout is a hard deadline for each attempt, redirects and the response body included. 0 turns it off
  • A variable name is checked before anything is sent, and an unusable one throws the same ApiException the API would, with requestId left null

Encryption

  • Envless::encryptValue and Envless::decryptValue, byte-for-byte compatible with the TypeScript, Python and Ruby SDKs, the CLI, the dashboard and the runtimes: AES-256-GCM under a PBKDF2-SHA-256 key with 200,000 iterations and the workspace salt. v1: and v2:<iterations>: envelopes both decrypt
  • deriveWorkspaceKey and importWorkspaceKey return an Envless\Crypto\WorkspaceKey that never prints its bytes and refuses to be serialised, for encryptWithKey and decryptWithKey across a batch
  • isCiphertext, passphraseStrength, variableNameValidation and Envless\Constants\EncryptionParameters
  • rotateWorkspacePassphrase(...) re-encrypts an environment's live variables and its version history, and lists in failures any version entry whose encrypted default cannot be rewritten because the entry's own value is not ciphertext
  • Plaintext, passphrases and workspace ids must be valid UTF-8, so binary data passed by mistake throws instead of producing ciphertext nothing else can read

Webhooks

  • Envless::verifyWebhookSignature(payload:, headers:, secret:) checks the HMAC-SHA256 signature in constant time and the timestamp drift, then returns the parsed event. It takes headers from an array in any case, $_SERVER, a PSR-7 request, or a Symfony or Laravel header bag

Runtime

  • PHP 8.2 or newer with the curl, json and openssl extensions, and no Composer dependencies
  • A PHPStan and Psalm array shape on Envless\Types for every body and response, and every method declares the ones it takes and returns
  • Every request carries User-Agent: envless-sdk-php/0.0.1