Getting started

Exports reference

Everything the envless package exports: the clients, the default client, crypto helpers, constants, exceptions and the TypedDict types.

envless-sdk installs one import root, envless. Everything below except the types is a name you import from envless, and the types live in envless.types.

Clients

ExportSignature
Envless(token=None, *, base_url=None, http_client=None, max_retries=None, timeout=None, user_agent=None, disable_update_notice=False)
AsyncEnvlessThe same arguments, with an httpx.AsyncClient for http_client
create_clientThe same class as Envless, under the TypeScript name
envlessA live handle on the default Envless, built from the environment on first use
init(token=None, *, base_url=None, http_client=None, max_retries=None, timeout=None, user_agent=None, disable_update_notice=False) -> Envless, installs the default client and returns it
get_client() -> Envless
reset_client() -> None

Every client reads ENVLESS_TOKEN and ENVLESS_API_ENDPOINT for the arguments you leave out. See Create a client and Async.

python
from envless import envless, init

init(timeout=10)

envless.products.list()

Crypto

ExportSignature
encrypt_value(plaintext: str, passphrase: str, workspace_unique_id: str) -> str
decrypt_value(ciphertext: str, passphrase: str, workspace_unique_id: str) -> str
encrypt_with_key(key: WorkspaceKey | bytes, plaintext: str) -> str
decrypt_with_key(key: WorkspaceKey | bytes, ciphertext: str) -> str
derive_workspace_key(passphrase: str, workspace_unique_id: str) -> WorkspaceKey
import_workspace_key(value: str) -> WorkspaceKey
is_ciphertext(value: object) -> TypeGuard[str]
passphrase_strength(passphrase: str) -> PassphraseValidation
WorkspaceKeyA derived or imported AES-256 key. WorkspaceKey(raw) wraps exactly 32 bytes and raises ValueError on any other length. It compares in constant time, is hashable, prints as WorkspaceKey(<redacted>), and bytes(key) returns the raw key
ENCRYPTION_PARAMETERSThe exact cryptographic constants, as a dict

They are synchronous functions: encryption is CPU work. See Encryption for the recipe and for why you should derive the key once when writing a batch.

Helpers

ExportSignature
rotate_workspace_passphrase(*, client, workspace_unique_id, from_, to, project, environment, product=None) -> RotatePassphraseResult, a coroutine with AsyncEnvless
verify_webhook_signature(*, payload: str | bytes, headers: Mapping[str, HeaderValue], secret: str, tolerance_seconds: float | None = None) -> WebhookEvent
variable_name_validation(name: object) -> NameValidation

rotate_workspace_passphrase re-encrypts live variables and version history for one environment, which is the part that is easy to forget. verify_webhook_signature is the receiver side of Webhooks. variable_name_validation returns {'valid': ..., 'error': ...} without raising, for checking a name in your own form or importer against the rule every write applies before it sends anything.

Exceptions

ExportNotes
EnvlessErrorThe base of every exception below.
EnvlessApiErrorThe API answered with a failure. Carries status, code, message, resource, field, request_id, retry_after_seconds.
EnvlessNetworkErrorNothing came back: connection failure or timeout. Carries message, is_timeout, cause.
DecryptionErrorA value does not decrypt. Also a ValueError.
WebhookVerificationErrorA delivery fails verification. Also a ValueError.

See Errors.

Constants

Enum-like values, so you never hard-code a string the API might reject. Each is a read-only namespace: read members as attributes, such as SCOPE_LEVELS.READ. Iterating one yields its values, in tests whether a string is one of them, and len() counts them, so if level not in SCOPE_LEVELS validates input.

ExportMembers
SCOPE_RESOURCESWORKSPACE, PRODUCTS, PRODUCT_ACCESS, PROJECTS, ENVIRONMENTS, VARIABLES, VERSIONS, MEMBERS, ROLES, KEYS, WEBHOOKS
SCOPE_LEVELSNONE, READ, WRITE
VARIABLE_TYPESTRING, NUMBER, BOOLEAN
VARIABLE_VISIBILITY_LEVELSSERVER, CLIENT
WEBHOOK_SIGNATURE_HEADERSID, TIMESTAMP and SIGNATURE, the three signed headers, then EVENT (Envless-Event, a copy of the event type) and DELIVERY (Envless-Delivery, the id of one delivery, shared by its automatic retries, while a replay gets a new one), which sit outside the signed string
PAGE_LIMITSMAX_LIMIT is 100, DEFAULT_LIMIT is 25
VERSIONThe package version, also __version__
python
import os

from envless import SCOPE_LEVELS, SCOPE_RESOURCES, VARIABLE_VISIBILITY_LEVELS, encrypt_value, envless

envless.keys.create(
    {
        'name': 'ci',
        'scopes': {
            SCOPE_RESOURCES.VARIABLES: SCOPE_LEVELS.READ,
            SCOPE_RESOURCES.VERSIONS: SCOPE_LEVELS.READ,
        },
    }
)

workspace_id = envless.me.get()['workspaceId']

envless.variables.create(
    'web',
    'production',
    {
        'name': 'NEXT_PUBLIC_API_URL',
        'value': encrypt_value('https://api.acme.com', os.environ['ENVLESS_PASSPHRASE'], workspace_id),
        'visibility': VARIABLE_VISIBILITY_LEVELS.CLIENT,
    },
)

Types

Every request body and every response is a TypedDict in envless.types, named as in TypeScript. They describe plain dicts, so they cost nothing at runtime: annotate with them, and mypy or pyright checks every key you read or write.

python
from envless import envless
from envless.types import Page, VariableInput, VariableResource

body: VariableInput = {'name': 'PORT', 'value': 'v1:...', 'type': 'number'}
page: Page[VariableResource] = envless.variables.list('api', 'production', limit=10)

Pages and pagination

Page, PaginationEnvelope, ProductAccessPage

Resources

IdentityResource, UserSummary, RoleSummary, ActorReference, ActorKeyReference, WorkspaceResource, CurrentWorkspaceResource, UpdatedWorkspaceResource, DeletedWorkspaceResource, CustomDomainResource, CustomDomainRecord, RemovedDomainResource, ProductResource, DeletedProductResource, ProductAccessEntry, GrantedProductAccessResource, RevokedProductAccessResource, ProjectResource, DeletedProjectResource, EnvironmentResource, EnvironmentSummaryResource, DeletedEnvironmentResource, VariableResource, DeletedVariableResource, DeletedVariablesResource, CreatedVariablesResource, VariableHistoryEvent, VersionResource, VersionDetailResource, VersionEntryResource, RolledBackVersionResource, ReencryptedEntriesResource, MemberResource, DeletedMemberResource, LeftWorkspaceResource, InviteResource, RevokedInviteResource, RoleResource, DeletedRoleResource, PermissionResource, PermissionsResource, KeyResource, CreatedKeyResource, DeletedKeyResource, WebhookResource, CreatedWebhookResource, DeletedWebhookResource, RotatedSecretResource, WebhookDeliveryResource, WebhookDeliveryDetailResource, RedeliveredWebhookResource, EventTypesResource

Inputs

WorkspaceCreate, WorkspacePatch, ProductCreate, ProductPatch, ProjectCreate, ProjectPatch, EnvironmentCreate, EnvironmentPatch, VariableInput, VariablePatch, VersionCreate, MemberInvite, MemberPatch, RoleCreate, RolePatch, KeyCreate, KeyPatch, WebhookCreate, WebhookPatch, ApplyChanges, ApplyBaselineEntry, ApplyUpdateEntry, ApplyResult, ReencryptEntryInput

Crypto and webhooks

EncryptionParameters, PassphraseValidation, NameValidation, RotatePassphraseResult, RotatePassphraseIssue, WebhookEvent, WebhookEventActor

Nested items

ApplyChangesDeletesItem, CreatedVariablesResourceCreatedItem, CreatedVariablesResourceSkippedItem, DeletedVariablesResourceDeletedItem, IdentityResourceKey, PermissionsResourceSystemRoles, ProjectResourceProduct, VersionDetailResourceVariablesItem

These name the dicts nested inside other results, for when you need to annotate one on its own. envless.types.client adds HeaderValue, which is str | Sequence[str] | None, and QueryValue, the values raw.request accepts in query. Options are keyword arguments rather than types, so there is no ListOptions or RequestScope in Python.

envless.constants holds the generated tables the SDK runs on. Only the names re-exported from envless itself are its public, stable surface.

Read shapes are not always the write shapes. workspace.get returns CurrentWorkspaceResource, with createdAt but no virtualEnvsEnabled, while workspace.update returns UpdatedWorkspaceResource, with virtualEnvsEnabled but no createdAt. The method pages call these out individually.

A worked example

python
import os

from envless import SCOPE_LEVELS, SCOPE_RESOURCES, encrypt_value, envless

passphrase = os.environ['ENVLESS_PASSPHRASE']
workspace_id = envless.me.get()['workspaceId']

product = envless.products.create({'name': 'Internal tools', 'slug': 'internal-tools'})
project = envless.projects.create({'name': 'API', 'slug': 'api', 'product': product['slug']})

for name in ('development', 'staging', 'production'):
    envless.environments.create(project['slug'], {'name': name, 'slug': name}, product=product['slug'])

envless.variables.create_many(
    'api',
    'production',
    [
        {'name': 'DATABASE_URL', 'value': encrypt_value(os.environ['DATABASE_URL'], passphrase, workspace_id)},
        {'name': 'PORT', 'value': encrypt_value('3000', passphrase, workspace_id), 'type': 'number'},
    ],
    product=product['slug'],
)

envless.versions.create('api', 'production', {'note': 'Initial provisioning'}, product=product['slug'])

key = envless.keys.create(
    {
        'name': 'api-runner',
        'scopes': {SCOPE_RESOURCES.VARIABLES: SCOPE_LEVELS.READ},
        'projectIds': [project['id']],
    }
)

print(key['secret'])