Envless publishes an official SDK for TypeScript, Python, Ruby and PHP. Each one is a typed client for the Envless API that administers a workspace from code: products, projects, environments, variables, versions, members, roles, keys and webhooks. The four are twins. Every one has all 113 methods across 13 namespaces, sends the same requests on the wire, retries the same way and raises the same error codes, so what you learn in one carries over to the others.
TypeScript
@goenvless/sdk on npm. Zero dependencies, on Node, Bun, Deno and Cloudflare Workers.
Python
envless-sdk on PyPI, imported as envless. A synchronous client, and AsyncEnvless for asyncio and trio.
Ruby
envless-sdk on RubyGems. RBS types for every call, and no runtime dependencies.
PHP
envless/sdk on Packagist. PHPStan and Psalm types for every call, and no Composer dependencies.
Install
npm install @goenvless/sdkpip install envless-sdkbundle add envless-sdkcomposer require envless/sdkEvery SDK authenticates with a personal access key (ev_sk_...), and each key is scoped to one workspace. Generate one at envless.cloud/dashboard/keys and give it to the client through ENVLESS_TOKEN. See Keys for naming, rotation and revocation, and Authentication for what a key grants.
The same client in every language
The clients mirror each other call for call. TypeScript and PHP use the same method names, and Python and Ruby use those names in snake_case.
import { createClient } from '@goenvless/sdk'
const envless = createClient({ token: process.env.ENVLESS_TOKEN })
const workspace = await envless.workspace.get()
for await (const project of envless.projects.iterate()) {
console.log(project.slug)
}import os
from envless import Envless
envless = Envless(os.environ['ENVLESS_TOKEN'])
workspace = envless.workspace.get()
for project in envless.projects.iterate():
print(project['slug'])require "envless/sdk"
envless = Envless::Client.new(token: ENV.fetch("ENVLESS_TOKEN"))
workspace = envless.workspace.get
envless.projects.iterate do |project|
puts "#{workspace[:slug]} #{project[:slug]}"
enduse Envless\Envless;
$envless = new Envless(token: (string) getenv('ENVLESS_TOKEN'));
$workspace = $envless->workspace->get();
foreach ($envless->projects->iterate() as $project) {
echo $workspace['slug'], ' ', $project['slug'], PHP_EOL;
}How they compare
| TypeScript | Python | Ruby | PHP | |
|---|---|---|---|---|
| Package | @goenvless/sdk | envless-sdk | envless-sdk | envless/sdk |
| Registry | npm | PyPI | RubyGems | Packagist |
| Requires | Node.js 20+, Bun, Deno, Workers | Python 3.10+ | Ruby 3.2+ | PHP 8.2+ |
| Imported as | @goenvless/sdk | envless | envless/sdk | Envless\Envless |
| Method names | listAll | list_all | list_all | listAll |
| Types | Bundled declarations | mypy and pyright | RBS | PHPStan and Psalm |
| Dependencies | None | httpx, anyio, cryptography, typing-extensions | None at runtime | None |
What every SDK shares
A key is bound to one workspace
The workspace comes from the key, never from the request. Reaching a second workspace means a second client.
Values are ciphertext, always
The server never sees plaintext and cannot encrypt for you, so every SDK ships the same encryption helpers. Encrypt before writing, decrypt after reading. See Encryption.
Lists come in three flavours
list for one page, listAll for everything, iterate for a stream, with list_all in Python and Ruby.
Errors carry the API code
Every API failure surfaces the API's stable machine-readable code, the same codes listed in Errors.
Coverage is enforced
The TypeScript SDK checks itself against openapi.json on every build, and the Python, Ruby and PHP SDKs replay every method against the requests the TypeScript SDK sends. A missing method, or one that drifts, fails the check.