SDKs & Integrations
Python SDK
Official Python SDK for KeyEnv.
Python SDK
Official Python SDK for KeyEnv with full type annotations.
Installation
pip install keyenvOr with poetry:
poetry add keyenvQuick Start
from keyenv import KeyEnv
import os
client = KeyEnv(token=os.environ["KEYENV_TOKEN"])
# Load secrets into os.environ
client.load_env("your-project-id", "production")
print(os.environ["DATABASE_URL"])Initialize the Client
from keyenv import KeyEnv
client = KeyEnv(
token="your-service-token",
timeout=30.0, # optional, default 30s
)Context Manager
Use as a context manager for automatic cleanup:
with KeyEnv(token="your-token") as client:
secrets = client.export_secrets("project-id", "production")Loading Secrets
Load into os.environ
The simplest way to use secrets in your application:
count = client.load_env("project-id", "production")
print(f"Loaded {count} secrets")
# Now use them
print(os.environ["DATABASE_URL"])
print(os.environ["API_KEY"])Export as Dictionary
Get secrets as a key-value dictionary:
env = client.export_secrets_as_dict("project-id", "production")
print(env["DATABASE_URL"])
print(env["API_KEY"])Export as List
Get secrets with metadata:
secrets = client.export_secrets("project-id", "production")
for secret in secrets:
print(f"{secret.key}={secret.value}")Managing Secrets
Get a Single Secret
secret = client.get_secret("project-id", "production", "DATABASE_URL")
print(secret.value)
print(secret.description)Set a Secret
Creates or updates a secret:
client.set_secret("project-id", "production", "API_KEY", "sk_live_...")
# With description
client.set_secret(
"project-id",
"production",
"API_KEY",
"sk_live_...",
description="Production API key"
)Delete a Secret
client.delete_secret("project-id", "production", "OLD_KEY")Bulk Operations
Bulk Import
Import multiple secrets at once:
from keyenv import BulkSecretItem
result = client.bulk_import(
"project-id",
"development",
[
BulkSecretItem(key="DATABASE_URL", value="postgres://localhost/mydb"),
BulkSecretItem(key="REDIS_URL", value="redis://localhost:6379"),
{"key": "API_KEY", "value": "sk_test_..."}, # Also accepts dicts
],
overwrite=True,
)
print(f"Created: {result.created}, Updated: {result.updated}")Generate .env File
env_content = client.generate_env_file("project-id", "production")
with open(".env", "w") as f:
f.write(env_content)Projects & Environments
List Projects
projects = client.list_projects()
for project in projects:
print(f"{project.name} ({project.id})")Get Project Details
project = client.get_project("project-id")
print(f"Project: {project.name}")
for env in project.environments:
print(f" - {env.name}")List Environments
environments = client.list_environments("project-id")
for env in environments:
print(env.name)Environment Permissions
Manage who can access secrets in each environment.
List Permissions
permissions = client.list_permissions("project-id", "production")
for perm in permissions:
print(f"{perm.user_email}: {perm.role}")Set Permission
# Grant write access to a user
client.set_permission("project-id", "production", "user-id", "write")Delete Permission
client.delete_permission("project-id", "production", "user-id")Get My Permissions
permissions, is_team_admin = client.get_my_permissions("project-id")
for perm in permissions:
print(f"{perm.environment_name}: {perm.role} (can_write: {perm.can_write})")Bulk Set Permissions
client.bulk_set_permissions("project-id", "production", [
{"user_id": "user-1", "role": "write"},
{"user_id": "user-2", "role": "read"},
])Project Defaults
# Get default permissions
defaults = client.get_project_defaults("project-id")
# Set default permissions for new team members
client.set_project_defaults("project-id", [
{"environment_name": "development", "default_role": "write"},
{"environment_name": "staging", "default_role": "read"},
{"environment_name": "production", "default_role": "none"},
])Error Handling
from keyenv import KeyEnv, KeyEnvError
try:
secret = client.get_secret("project-id", "production", "MISSING_KEY")
except KeyEnvError as e:
print(f"Error {e.status}: {e.message}")
if e.status == 401:
print("Invalid or expired token")
elif e.status == 403:
print("Access denied")
elif e.status == 404:
print("Secret not found")Type Hints
The SDK includes full type annotations for better IDE support:
from keyenv import Secret, SecretWithValue, Project, EnvironmentAPI Reference
Constructor Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
token | str | Yes | - | Service token |
timeout | float | No | 30.0 | Request timeout (seconds) |
Methods
| Method | Description |
|---|---|
get_current_user() | Get current user/token info |
list_projects() | List all accessible projects |
get_project(id) | Get project with environments |
list_environments(project_id) | List environments in a project |
list_secrets(project_id, env) | List secret keys (no values) |
export_secrets(project_id, env) | Export secrets with values |
export_secrets_as_dict(project_id, env) | Export as dictionary |
get_secret(project_id, env, key) | Get single secret |
set_secret(project_id, env, key, value) | Create or update secret |
delete_secret(project_id, env, key) | Delete secret |
bulk_import(project_id, env, secrets) | Bulk import secrets |
load_env(project_id, env) | Load secrets into os.environ |
generate_env_file(project_id, env) | Generate .env file content |
list_permissions(project_id, env) | List permissions for an environment |
set_permission(project_id, env, user_id, role) | Set user's permission |
delete_permission(project_id, env, user_id) | Delete user's permission |
bulk_set_permissions(project_id, env, permissions) | Bulk set permissions |
get_my_permissions(project_id) | Get current user's permissions |
get_project_defaults(project_id) | Get default permissions |
set_project_defaults(project_id, defaults) | Set default permissions |
Examples
FastAPI Application
from fastapi import FastAPI
from keyenv import KeyEnv
import os
# Load secrets at startup
client = KeyEnv(token=os.environ["KEYENV_TOKEN"])
client.load_env(os.environ["KEYENV_PROJECT"], "production")
app = FastAPI()
@app.get("/")
async def root():
return {"status": "ok"}
@app.get("/config")
async def config():
return {
"api_url": os.environ.get("API_URL"),
# Don't expose sensitive secrets!
}Django Settings
# settings.py
from keyenv import KeyEnv
import os
# Load secrets before Django initializes
if os.environ.get("KEYENV_TOKEN"):
client = KeyEnv(token=os.environ["KEYENV_TOKEN"])
client.load_env(os.environ["KEYENV_PROJECT"], os.environ.get("ENV", "development"))
# Now use secrets in settings
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"HOST": os.environ.get("DB_HOST"),
"NAME": os.environ.get("DB_NAME"),
"USER": os.environ.get("DB_USER"),
"PASSWORD": os.environ.get("DB_PASSWORD"),
}
}
SECRET_KEY = os.environ.get("DJANGO_SECRET_KEY")Flask Application
from flask import Flask
from keyenv import KeyEnv
import os
# Load secrets
client = KeyEnv(token=os.environ["KEYENV_TOKEN"])
client.load_env(os.environ["KEYENV_PROJECT"], "production")
app = Flask(__name__)
app.config["SECRET_KEY"] = os.environ["FLASK_SECRET_KEY"]
@app.route("/")
def hello():
return {"status": "ok"}Script/CLI Tool
#!/usr/bin/env python3
import argparse
from keyenv import KeyEnv
import os
def main():
parser = argparse.ArgumentParser()
parser.add_argument("--env", default="development")
args = parser.parse_args()
client = KeyEnv(token=os.environ["KEYENV_TOKEN"])
secrets = client.export_secrets_as_dict("my-project", args.env)
print(f"Database: {secrets['DATABASE_URL']}")
# Do something with secrets...
if __name__ == "__main__":
main()