Getting started

Python SDK overview

The official Python client for the Envless API. Every workspace, product, project, environment, variable, version, member, role, key and webhook, driven from Python, synchronously or with asyncio.

envless-sdk is the official Python client for the Envless API, imported as envless. It has every method of the TypeScript SDK, all 113 across 13 namespaces, under the same names in snake_case, typed end to end, with a synchronous client and an asynchronous one that share every method.

pip install envless-sdk

Set ENVLESS_TOKEN to an API key and the ready made envless client works with no setup code at all.

python
from envless import envless

workspace = envless.workspace.get()

for project in envless.projects.iterate():
    print(project['slug'])

Prefer an explicit instance, or need more than one workspace? Envless() gives you one to pass around, and AsyncEnvless() is the same client for asyncio and trio. See Create a client and Async.

What this is, and what it is not

The Python SDK administers a workspace from code. It is the Python 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 Python application loads its own variables at boot.

envless-sdk@goenvless/sdk@goenvless/cli
PurposeAdministers a workspace from PythonAdministers a workspace from TypeScriptRuns the envless command, and loads variables into any process
AudienceProvisioning scripts, Django or FastAPI 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
Shapeenvless.projects.create({...})envless.projects.create({ ... })envless run -- python app.py

If you want your Python app to read DATABASE_URL at boot, use the Python runtime, envless-env, or wrap it with envless run -- python app.py, which decrypts the environment and hands it to the process as ordinary environment variables, or write a .env file with envless sync. os.environ then has everything. If you want a script that creates a project, adds three environments and seeds their variables, you are in the right place.

Design

Typed end to end

Every request body and every response has a TypedDict in envless.types, so your editor completes the keys and mypy or pyright catches a misspelt one. The package ships py.typed.

Sync and async

Envless for scripts and threads, AsyncEnvless for asyncio and trio. Same methods, same arguments, same results, built from one source so they cannot drift apart.

Four dependencies

httpx for the transport, anyio for the async client, cryptography for AES-GCM, and typing-extensions. PBKDF2 comes from the standard library. Python 3.10 or newer.

Honest errors

Every API failure is an EnvlessApiError carrying the API's stable machine-readable code, and every transport failure is an EnvlessNetworkError. Both inherit EnvlessError.

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 dicts with the API field names

A request body is a plain dict and so is every result, keyed exactly as the API reference spells them: 'defaultValue', 'updatedAt', 'virtualEnvsEnabled'. Method names and keyword arguments are snake_case, field names are not.

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, list_all for everything, iterate for a stream. See Pagination.

Sync environments with apply, not a loop

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 raises the same typed errors.

Every method has a twin

Each Python 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 through both Python clients 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. Ciphertext from this package, the TypeScript SDK, the CLI and the dashboard is interchangeable.